In [1]:
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import seaborn as sns
import ast
from scipy.stats import ttest_ind, chi2_contingency, zscore

# Preprocesamiento y Modelado
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import StandardScaler, LabelEncoder
from sklearn.linear_model import LogisticRegression
from sklearn.ensemble import RandomForestClassifier, GradientBoostingClassifier
from sklearn.feature_selection import VarianceThreshold
from sklearn.impute import SimpleImputer # Para manejar NaNs si aún existen

from sklearn.metrics import (
    accuracy_score,
    precision_score,
    recall_score,
    f1_score,
    roc_auc_score,
    confusion_matrix,
    ConfusionMatrixDisplay,
    classification_report,
    RocCurveDisplay
)

from statsmodels.stats.outliers_influence import variance_inflation_factor
from statsmodels.tools.tools import add_constant
from statsmodels.stats.outliers_influence import variance_inflation_factor
from statsmodels.tools.tools import add_constant

# Configuraciones para mejor visualización
%matplotlib inline
plt.style.use('seaborn-v0_8-whitegrid')
pd.set_option('display.max_columns', None) # Mostrar todas las columnas
import warnings
warnings.filterwarnings('ignore') # Ignorar warnings para limpieza

Descriptivos datos de CV extraidos¶

In [2]:
file_path = "../Bases/base_cvs/base_cvs_mejorado.csv"  # Ajusta el path si es necesario
df = pd.read_csv(file_path)
df = df.drop(columns=["Unnamed: 0", "archivo"], errors="ignore")  # errors="ignore" evita fallos si ya no existe
In [3]:
df
Out[3]:
Categoria Original Passed status_procesamiento Numero de Paginas Cantidad de Palabras Densidad Informacion (%) Formato Texto (Lineas) Orden Temporal Fechas Detectadas (Count) Formato Fecha Más Común Fuente principal Tamaño cuerpo probable Legibilidad general Variedad de fuentes Variedad de tamaños Consistencia tamaños fuente Consistencia márgenes (aprox) Uso de negritas (estimado %) Uso de cursivas (estimado %) Uso de colores (texto) Uso de colores (dibujos) Porcentaje Lenguaje Técnico Porcentaje Lenguaje Genérico LinkedIn GitHub Website/Otro Deteccion Foto Perfil Cantidad de imágenes Tiene Elementos Graficos Lineas_education Lineas_work_experience Lineas_skills Lineas_certifications Lineas_achievements Lineas_professional_profile Lineas_languages Lineas_projects Lineas_publications Lineas_training_courses Lineas_volunteer_work Seccion_education Seccion_work_experience Seccion_skills Seccion_certifications Seccion_achievements Seccion_professional_profile Seccion_languages Seccion_projects Seccion_publications Seccion_training_courses Seccion_volunteer_work texto_extraido_len Tamaño de fuente más usado Tamaños fuente detectados
0 Exitoso 1 Completado 2 493 5.71 Viñetas Orden Temporal Detectado 3 Mon YYYY (EN) Garamond-Bold 12 Buena 7 5 Consistente Consistente 34.4 91.7 Sí Sí 3.72 96.28 True False True No se detectaron imágenes candidatas 0 False 6 2 26 0 0 0 0 9 0 0 0 True True True True False True False True True True False 3692 12 [10, 12, 16, 18, 24]
1 Exitoso 1 Completado 1 388 8.09 Viñetas Pocas Fechas 1 MM/YYYY NotoSansZanabazarSquare- 9 Potencialmente Deficiente 1 1 Consistente Consistente 0.0 100.0 No Sí 9.61 90.39 False False True Posible Foto Detectada 9 True 8 12 3 0 0 3 1 0 7 0 0 True True True True False True True True True True False 2703 9 [9]
2 Exitoso 1 Completado 1 378 8.27 Mixto Pocas Fechas 0 Mon YYYY (EN) ArialMT 10 Buena 3 4 Consistente Consistente 21.8 100.0 Sí No 8.58 91.42 False False False No se detectaron imágenes candidatas 0 True 3 38 1 0 0 0 0 0 0 0 0 True True True True False True True True True True True 2761 10 [8, 10, 12, 22]
3 Exitoso 1 Completado 4 656 3.54 Viñetas Orden Temporal Detectado 2 SpaCy DATE (Sin clasificar) Montserrat-Regular 10 Buena 4 12 Inconsistente Inconsistente 16.2 100.0 No Sí 6.67 93.33 False False False Posible Foto Detectada 3 True 25 8 3 0 0 0 17 0 0 18 0 True True True False False True True True True True False 4732 10 [7, 8, 9, 10, 11, 12, 13, 14, 15, 18, 19, 43]
4 Exitoso 1 Completado 3 160 4.71 Viñetas Pocas Fechas 0 YYYY Lato-Regular 10 Buena 6 7 Inconsistente Consistente 31.2 5.2 Sí No 11.29 88.71 True True False Posible Foto Detectada 5 True 0 7 0 0 2 5 8 2 3 1 0 True True True True True True True True True True True 4562 10 [9, 10, 11, 12, 14, 16, 24]
... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ...
630 No Exitoso 0 Completado 6 1372 4.37 Viñetas Pocas Fechas 0 Mon YYYY (EN) Calibri 11 Buena 8 6 Inconsistente Inconsistente 32.7 36.8 Sí Sí 6.72 93.28 False False True Posible Foto Detectada 8 True 6 5 0 6 1 0 3 3 6 6 0 True True True True True True True True True True False 8464 11 [9, 11, 12, 13, 14, 20]
631 No Exitoso 0 Completado 10 3729 7.54 Viñetas Orden Temporal Detectado 3 YYYY Calibri 11 Buena 7 8 Inconsistente Consistente 8.1 5.4 No Sí 2.71 97.29 False False False No se detectaron imágenes candidatas 1 True 0 0 2 4 0 12 0 34 0 5 0 True False True True True True True True True True False 25210 11 [6, 8, 10, 11, 12, 16, 18, 24]
632 No Exitoso 0 Completado 3 899 6.13 Viñetas Pocas Fechas 1 SpaCy DATE (Sin clasificar) OpenSans-Bold 11 Buena 4 6 Inconsistente Consistente 62.7 4.5 No No 5.04 94.96 False False False No se detectaron imágenes candidatas 0 True 5 8 12 0 17 1 1 35 0 0 4 True True True True True True True True True True True 6154 11 [10, 11, 12, 14, 16, 22]
633 No Exitoso 0 Completado 1 185 3.93 Viñetas Orden Temporal Detectado 2 YYYY DidactGothic-Regular 10 Buena 2 4 Consistente Consistente 0.0 100.0 No Sí 6.25 93.75 False False False No se detectaron imágenes candidatas 0 True 0 1 5 0 0 5 5 3 0 2 0 True True True True False True True True True True False 1313 10 [10, 12, 16, 34]
634 No Exitoso 0 Completado 4 534 5.95 Viñetas Pocas Fechas 0 Mes YYYY (ES Comp) ComicSansMS 11 Buena 3 2 Consistente Inconsistente 39.9 0.5 Sí Sí 5.55 94.45 True False False Posible Foto Detectada 2 True 1 0 2 4 1 0 1 1 4 0 0 True True True True True True True True True True True 7693 11 [10, 11]

635 rows × 54 columns

In [4]:
# Análisis descriptivo

# Resumen de estadísticas descriptivas
print("Resumen de estadísticas descriptivas:")
print(df.describe())

# Histogramas para cada variable numérica
numerical_cols = df.select_dtypes(include=['number']).columns
df[numerical_cols].hist(figsize=(15, 10), bins=15, edgecolor='black')
plt.suptitle("Histogramas de variables numéricas", fontsize=16)
plt.tight_layout(rect=[0, 0, 1, 0.96])
plt.show()

# Matriz de correlación
corr_matrix = df[numerical_cols].corr()
plt.figure(figsize=(10, 8))
sns.heatmap(corr_matrix, annot=True, cmap='coolwarm', fmt=".2f")
plt.title("Matriz de correlaciones", fontsize=16)
plt.show()
Resumen de estadísticas descriptivas:
           Passed  Numero de Paginas  Cantidad de Palabras  \
count  635.000000         635.000000            635.000000   
mean     0.422047           2.812598            564.771654   
std      0.494275           2.361862            451.408217   
min      0.000000           1.000000              0.000000   
25%      0.000000           2.000000            256.000000   
50%      0.000000           2.000000            480.000000   
75%      1.000000           3.000000            750.000000   
max      1.000000          38.000000           3729.000000   

       Densidad Informacion (%)  Fechas Detectadas (Count)  \
count                635.000000                 635.000000   
mean                   5.841354                   1.338583   
std                    2.474386                   1.902267   
min                    0.000000                   0.000000   
25%                    4.280000                   0.000000   
50%                    5.560000                   1.000000   
75%                    7.005000                   2.000000   
max                   18.940000                  14.000000   

       Tamaño cuerpo probable  Variedad de fuentes  Variedad de tamaños  \
count              635.000000           635.000000           635.000000   
mean                10.023622             4.585827             5.103937   
std                  4.070484             2.231857             2.400427   
min                  0.000000             0.000000             0.000000   
25%                  9.000000             3.000000             4.000000   
50%                 10.000000             4.000000             5.000000   
75%                 11.000000             6.000000             6.000000   
max                100.000000            17.000000            17.000000   

       Uso de negritas (estimado %)  Uso de cursivas (estimado %)  \
count                    635.000000                    635.000000   
mean                      19.723937                     54.562047   
std                       13.177758                     44.804869   
min                        0.000000                      0.000000   
25%                       10.300000                      3.350000   
50%                       19.200000                     75.200000   
75%                       27.950000                    100.000000   
max                      100.000000                    100.000000   

       Porcentaje Lenguaje Técnico  Porcentaje Lenguaje Genérico  \
count                   635.000000                    635.000000   
mean                      7.351480                     92.648520   
std                       3.989495                      3.989495   
min                       0.000000                     76.360000   
25%                       4.610000                     90.765000   
50%                       6.690000                     93.310000   
75%                       9.235000                     95.390000   
max                      23.640000                    100.000000   

       Cantidad de imágenes  Lineas_education  Lineas_work_experience  \
count            635.000000        635.000000              635.000000   
mean               3.551181          6.125984               11.674016   
std               10.534088          8.303578               22.353467   
min                0.000000          0.000000                0.000000   
25%                0.000000          1.000000                1.000000   
50%                1.000000          3.000000                4.000000   
75%                2.000000          7.000000               13.000000   
max              115.000000         78.000000              192.000000   

       Lineas_skills  Lineas_certifications  Lineas_achievements  \
count     635.000000             635.000000           635.000000   
mean        5.384252               2.486614             1.587402   
std         9.643998               6.505595             5.714542   
min         0.000000               0.000000             0.000000   
25%         0.000000               0.000000             0.000000   
50%         2.000000               0.000000             0.000000   
75%         6.000000               2.000000             0.000000   
max       124.000000              67.000000            75.000000   

       Lineas_professional_profile  Lineas_languages  Lineas_projects  \
count                   635.000000        635.000000       635.000000   
mean                      6.100787          4.346457         4.669291   
std                      11.630859          6.589086         8.915884   
min                       0.000000          0.000000         0.000000   
25%                       0.000000          0.000000         0.000000   
50%                       2.000000          2.000000         0.000000   
75%                       7.000000          6.000000         5.000000   
max                     127.000000         58.000000        72.000000   

       Lineas_publications  Lineas_training_courses  Lineas_volunteer_work  \
count           635.000000               635.000000             635.000000   
mean              6.322835                 3.711811               1.913386   
std              11.582976                 7.780533               5.090078   
min               0.000000                 0.000000               0.000000   
25%               0.000000                 0.000000               0.000000   
50%               1.000000                 0.000000               0.000000   
75%               7.000000                 4.000000               1.000000   
max             107.000000                69.000000              42.000000   

       texto_extraido_len  Tamaño de fuente más usado  
count          635.000000                  635.000000  
mean          4812.239370                   10.023622  
std           2993.282002                    4.070484  
min              0.000000                    0.000000  
25%           2834.500000                    9.000000  
50%           4097.000000                   10.000000  
75%           6079.000000                   11.000000  
max          25210.000000                  100.000000  
No description has been provided for this image
No description has been provided for this image

Descriptivos variables categóricas¶

In [5]:
# Seleccionar columnas categóricas
categorical_cols = df.select_dtypes(include=["object", "category", "bool"]).columns

# Iterar sobre cada columna categórica para mostrar conteos y gráficas
for col in categorical_cols:
    print(f"Distribución de valores para '{col}':")
    print(df[col].value_counts(), "\n")

    # Gráfico de barras
    plt.figure(figsize=(8, 4))
    df[col].value_counts().plot(kind='bar', color='skyblue', edgecolor='black')
    plt.title(f"Gráfico de barras para '{col}'")
    plt.xlabel(col)
    plt.ylabel("Frecuencia")
    plt.xticks(rotation=45, ha='right')
    plt.tight_layout()
    plt.show()

    # Gráfico de pastel
    plt.figure(figsize=(6, 6))
    df[col].value_counts().plot(kind='pie', autopct='%1.1f%%', startangle=90, colors=plt.cm.Paired.colors)
    plt.title(f"Gráfico de pastel para '{col}'")
    plt.ylabel("")  # Eliminar el texto del eje Y
    plt.tight_layout()
    plt.show()
Distribución de valores para 'Categoria Original':
Categoria Original
No Exitoso    367
Exitoso       268
Name: count, dtype: int64 

No description has been provided for this image
No description has been provided for this image
Distribución de valores para 'status_procesamiento':
status_procesamiento
Completado                          626
Advertencia: No se extrajo texto      9
Name: count, dtype: int64 

No description has been provided for this image
No description has been provided for this image
Distribución de valores para 'Formato Texto (Lineas)':
Formato Texto (Lineas)
Viñetas          473
Mixto            133
Párrafos          20
Indeterminado      9
Name: count, dtype: int64 

No description has been provided for this image
No description has been provided for this image
Distribución de valores para 'Orden Temporal':
Orden Temporal
Pocas Fechas                439
Orden Temporal Detectado    196
Name: count, dtype: int64 

No description has been provided for this image
No description has been provided for this image
Distribución de valores para 'Formato Fecha Más Común':
Formato Fecha Más Común
YYYY                           251
Mon YYYY (EN)                  104
SpaCy DATE (Sin clasificar)     91
Month YYYY (EN)                 72
MM/YYYY                         59
Mes YYYY (ES Comp)              13
DD/MM/YYYY                      12
Rango YYYY-YYYY                 11
MM-YYYY                          5
YYYY (SpaCy)                     1
Name: count, dtype: int64 

No description has been provided for this image
No description has been provided for this image
Distribución de valores para 'Fuente principal':
Fuente principal
ArialMT                     84
Calibri                     65
Tahoma                      31
TimesNewRomanPSMT           25
Roboto-Regular              23
                            ..
NotoSansZanabazarSquare-     1
Lato-Bold                    1
Amiko-SemiBold               1
FiraSans-Light               1
ComicSansMS                  1
Name: count, Length: 158, dtype: int64 

No description has been provided for this image
No description has been provided for this image
Distribución de valores para 'Legibilidad general':
Legibilidad general
Buena                        431
Potencialmente Deficiente    190
Vacío                         14
Name: count, dtype: int64 

No description has been provided for this image
No description has been provided for this image
Distribución de valores para 'Consistencia tamaños fuente':
Consistencia tamaños fuente
Consistente      372
Inconsistente    249
Name: count, dtype: int64 

No description has been provided for this image
No description has been provided for this image
Distribución de valores para 'Consistencia márgenes (aprox)':
Consistencia márgenes (aprox)
Consistente      508
Inconsistente    113
Name: count, dtype: int64 

No description has been provided for this image
No description has been provided for this image
Distribución de valores para 'Uso de colores (texto)':
Uso de colores (texto)
Sí    444
No    191
Name: count, dtype: int64 

No description has been provided for this image
No description has been provided for this image
Distribución de valores para 'Uso de colores (dibujos)':
Uso de colores (dibujos)
Sí    401
No    234
Name: count, dtype: int64 

No description has been provided for this image
No description has been provided for this image
Distribución de valores para 'LinkedIn':
LinkedIn
False    437
True     198
Name: count, dtype: int64 

No description has been provided for this image
No description has been provided for this image
Distribución de valores para 'GitHub':
GitHub
False    564
True      71
Name: count, dtype: int64 

No description has been provided for this image
No description has been provided for this image
Distribución de valores para 'Website/Otro':
Website/Otro
False    517
True     118
Name: count, dtype: int64 

No description has been provided for this image
No description has been provided for this image
Distribución de valores para 'Deteccion Foto Perfil':
Deteccion Foto Perfil
No se detectaron imágenes candidatas    434
Posible Foto Detectada                  201
Name: count, dtype: int64 

No description has been provided for this image
No description has been provided for this image
Distribución de valores para 'Tiene Elementos Graficos':
Tiene Elementos Graficos
True     360
False    275
Name: count, dtype: int64 

No description has been provided for this image
No description has been provided for this image
Distribución de valores para 'Seccion_education':
Seccion_education
True     615
False     20
Name: count, dtype: int64 

No description has been provided for this image
No description has been provided for this image
Distribución de valores para 'Seccion_work_experience':
Seccion_work_experience
True     617
False     18
Name: count, dtype: int64 

No description has been provided for this image
No description has been provided for this image
Distribución de valores para 'Seccion_skills':
Seccion_skills
True     586
False     49
Name: count, dtype: int64 

No description has been provided for this image
No description has been provided for this image
Distribución de valores para 'Seccion_certifications':
Seccion_certifications
True     559
False     76
Name: count, dtype: int64 

No description has been provided for this image
No description has been provided for this image
Distribución de valores para 'Seccion_achievements':
Seccion_achievements
False    413
True     222
Name: count, dtype: int64 

No description has been provided for this image
No description has been provided for this image
Distribución de valores para 'Seccion_professional_profile':
Seccion_professional_profile
True     587
False     48
Name: count, dtype: int64 

No description has been provided for this image
No description has been provided for this image
Distribución de valores para 'Seccion_languages':
Seccion_languages
True     564
False     71
Name: count, dtype: int64 

No description has been provided for this image
No description has been provided for this image
Distribución de valores para 'Seccion_projects':
Seccion_projects
True     562
False     73
Name: count, dtype: int64 

No description has been provided for this image
No description has been provided for this image
Distribución de valores para 'Seccion_publications':
Seccion_publications
True     619
False     16
Name: count, dtype: int64 

No description has been provided for this image
No description has been provided for this image
Distribución de valores para 'Seccion_training_courses':
Seccion_training_courses
True     514
False    121
Name: count, dtype: int64 

No description has been provided for this image
No description has been provided for this image
Distribución de valores para 'Seccion_volunteer_work':
Seccion_volunteer_work
False    338
True     297
Name: count, dtype: int64 

No description has been provided for this image
No description has been provided for this image
Distribución de valores para 'Tamaños fuente detectados':
Tamaños fuente detectados
[]                         14
[10, 12, 14, 24]           14
[10, 11, 12]               12
[10, 12]                   10
[10, 11, 12, 14]            9
                           ..
[8, 9, 10, 12, 17, 25]      1
[6, 10, 11, 12, 15, 36]     1
[8, 9, 10, 18]              1
[8, 10, 11, 13]             1
[10, 12, 16, 34]            1
Name: count, Length: 472, dtype: int64 

No description has been provided for this image
No description has been provided for this image

Descriptivos variable objetivo¶

In [6]:
# Seleccionar columnas categóricas
categorical_cols = df.select_dtypes(include=['object', 'category', 'bool']).columns

# Imprimir tablas cruzadas y gráficos de barras para cada variable categórica con 'Passed'
for col in categorical_cols:
    print(f"Tabla cruzada entre 'Passed' y '{col}':")
    crosstab = pd.crosstab(df[col], df['Passed'])
    print(crosstab, "\n")

    # Gráfico de barras agrupadas
    crosstab.plot(kind='bar', stacked=True, figsize=(8, 4), color=['lightcoral', 'skyblue'])
    plt.title(f"Relación entre '{col}' y 'Passed'")
    plt.xlabel(col)
    plt.ylabel('Frecuencia')
    plt.xticks(rotation=45, ha='right')
    plt.legend(title='Passed', labels=['0 (No Passed)', '1 (Passed)'])
    plt.tight_layout()
    plt.show()
Tabla cruzada entre 'Passed' y 'Categoria Original':
Passed                0    1
Categoria Original          
Exitoso               0  268
No Exitoso          367    0 

No description has been provided for this image
Tabla cruzada entre 'Passed' y 'status_procesamiento':
Passed                              0    1
status_procesamiento                      
Advertencia: No se extrajo texto    5    4
Completado                        362  264 

No description has been provided for this image
Tabla cruzada entre 'Passed' y 'Formato Texto (Lineas)':
Passed                    0    1
Formato Texto (Lineas)          
Indeterminado             5    4
Mixto                    73   60
Párrafos                 10   10
Viñetas                 279  194 

No description has been provided for this image
Tabla cruzada entre 'Passed' y 'Orden Temporal':
Passed                      0    1
Orden Temporal                    
Orden Temporal Detectado  112   84
Pocas Fechas              255  184 

No description has been provided for this image
Tabla cruzada entre 'Passed' y 'Formato Fecha Más Común':
Passed                         0    1
Formato Fecha Más Común              
DD/MM/YYYY                     7    5
MM-YYYY                        1    4
MM/YYYY                       27   32
Mes YYYY (ES Comp)             7    6
Mon YYYY (EN)                 64   40
Month YYYY (EN)               43   29
Rango YYYY-YYYY                4    7
SpaCy DATE (Sin clasificar)   59   32
YYYY                         142  109
YYYY (SpaCy)                   1    0 

No description has been provided for this image
Tabla cruzada entre 'Passed' y 'Fuente principal':
Passed                    0  1
Fuente principal              
AdelleSansDevanagari-Reg  0  1
Aileron-Regular           0  1
Aleo-Regular              1  0
Amiko-Regular             1  0
Amiko-SemiBold            0  1
...                      .. ..
Ubuntu-Regular            2  6
Unnamed-T3                3  8
Verdana                   8  5
___WRD_EMBED_SUB_43       0  1
___WRD_EMBED_SUB_44       1  0

[158 rows x 2 columns] 

No description has been provided for this image
Tabla cruzada entre 'Passed' y 'Legibilidad general':
Passed                       0    1
Legibilidad general                
Buena                      257  174
Potencialmente Deficiente  102   88
Vacío                        8    6 

No description has been provided for this image
Tabla cruzada entre 'Passed' y 'Consistencia tamaños fuente':
Passed                         0    1
Consistencia tamaños fuente          
Consistente                  217  155
Inconsistente                142  107 

No description has been provided for this image
Tabla cruzada entre 'Passed' y 'Consistencia márgenes (aprox)':
Passed                           0    1
Consistencia márgenes (aprox)          
Consistente                    296  212
Inconsistente                   63   50 

No description has been provided for this image
Tabla cruzada entre 'Passed' y 'Uso de colores (texto)':
Passed                    0    1
Uso de colores (texto)          
No                      120   71
Sí                      247  197 

No description has been provided for this image
Tabla cruzada entre 'Passed' y 'Uso de colores (dibujos)':
Passed                      0    1
Uso de colores (dibujos)          
No                        135   99
Sí                        232  169 

No description has been provided for this image
Tabla cruzada entre 'Passed' y 'LinkedIn':
Passed      0    1
LinkedIn          
False     252  185
True      115   83 

No description has been provided for this image
Tabla cruzada entre 'Passed' y 'GitHub':
Passed    0    1
GitHub          
False   327  237
True     40   31 

No description has been provided for this image
Tabla cruzada entre 'Passed' y 'Website/Otro':
Passed          0    1
Website/Otro          
False         311  206
True           56   62 

No description has been provided for this image
Tabla cruzada entre 'Passed' y 'Deteccion Foto Perfil':
Passed                                  0    1
Deteccion Foto Perfil                         
No se detectaron imágenes candidatas  243  191
Posible Foto Detectada                124   77 

No description has been provided for this image
Tabla cruzada entre 'Passed' y 'Tiene Elementos Graficos':
Passed                      0    1
Tiene Elementos Graficos          
False                     160  115
True                      207  153 

No description has been provided for this image
Tabla cruzada entre 'Passed' y 'Seccion_education':
Passed               0    1
Seccion_education          
False               13    7
True               354  261 

No description has been provided for this image
Tabla cruzada entre 'Passed' y 'Seccion_work_experience':
Passed                     0    1
Seccion_work_experience          
False                     11    7
True                     356  261 

No description has been provided for this image
Tabla cruzada entre 'Passed' y 'Seccion_skills':
Passed            0    1
Seccion_skills          
False            33   16
True            334  252 

No description has been provided for this image
Tabla cruzada entre 'Passed' y 'Seccion_certifications':
Passed                    0    1
Seccion_certifications          
False                    48   28
True                    319  240 

No description has been provided for this image
Tabla cruzada entre 'Passed' y 'Seccion_achievements':
Passed                  0    1
Seccion_achievements          
False                 243  170
True                  124   98 

No description has been provided for this image
Tabla cruzada entre 'Passed' y 'Seccion_professional_profile':
Passed                          0    1
Seccion_professional_profile          
False                          30   18
True                          337  250 

No description has been provided for this image
Tabla cruzada entre 'Passed' y 'Seccion_languages':
Passed               0    1
Seccion_languages          
False               48   23
True               319  245 

No description has been provided for this image
Tabla cruzada entre 'Passed' y 'Seccion_projects':
Passed              0    1
Seccion_projects          
False              48   25
True              319  243 

No description has been provided for this image
Tabla cruzada entre 'Passed' y 'Seccion_publications':
Passed                  0    1
Seccion_publications          
False                  12    4
True                  355  264 

No description has been provided for this image
Tabla cruzada entre 'Passed' y 'Seccion_training_courses':
Passed                      0    1
Seccion_training_courses          
False                      80   41
True                      287  227 

No description has been provided for this image
Tabla cruzada entre 'Passed' y 'Seccion_volunteer_work':
Passed                    0    1
Seccion_volunteer_work          
False                   201  137
True                    166  131 

No description has been provided for this image
Tabla cruzada entre 'Passed' y 'Tamaños fuente detectados':
Passed                              0  1
Tamaños fuente detectados               
[0, 1, 5, 9, 10, 12, 36]            1  0
[0, 11, 12, 13, 14, 18]             1  0
[0, 5, 6, 7, 8, 9, 10, 11, 13, 16]  0  1
[0, 6, 8, 9, 10, 20]                1  0
[0, 9, 11, 14, 22]                  1  0
...                                .. ..
[9, 12, 24]                         1  0
[9, 12, 26]                         1  0
[9, 13, 32]                         0  1
[9]                                 0  1
[]                                  8  6

[472 rows x 2 columns] 

No description has been provided for this image

Identificar variables con baja varianza¶

In [7]:
threshold = 0.01

# Seleccionar solo variables numéricas
numerical_cols = df.select_dtypes(include=['number'])

# Usar VarianceThreshold para identificar columnas con baja varianza
selector = VarianceThreshold(threshold=threshold)
selector.fit(numerical_cols)

# Obtener las columnas con baja varianza
low_variance_cols = numerical_cols.columns[~selector.get_support()]

# Imprimir el resultado
print("Columnas con baja varianza (<= 0.01):")
for col in low_variance_cols:
    print(f"- {col}: Varianza = {numerical_cols[col].var():.6f}")
Columnas con baja varianza (<= 0.01):

Detectar outliers¶

In [8]:
numerical_cols = df.select_dtypes(include=['number']).columns

for col in numerical_cols:
    plt.figure(figsize=(8, 4))
    sns.boxplot(data=df, x=col)
    plt.title(f"Boxplot para '{col}'")
    plt.xlabel(col)
    plt.tight_layout()
    plt.show()
No description has been provided for this image
No description has been provided for this image
No description has been provided for this image
No description has been provided for this image
No description has been provided for this image
No description has been provided for this image
No description has been provided for this image
No description has been provided for this image
No description has been provided for this image
No description has been provided for this image
No description has been provided for this image
No description has been provided for this image
No description has been provided for this image
No description has been provided for this image
No description has been provided for this image
No description has been provided for this image
No description has been provided for this image
No description has been provided for this image
No description has been provided for this image
No description has been provided for this image
No description has been provided for this image
No description has been provided for this image
No description has been provided for this image
No description has been provided for this image
No description has been provided for this image
No description has been provided for this image

Outliers con z-score¶

In [9]:
# Calcular el Z-score para todas las variables numéricas
z_scores = df[numerical_cols].apply(zscore)

# Umbral para definir valores atípicos (e.g., Z > 3 o Z < -3)
threshold = 3

# Identificar outliers en cada columna
outliers_zscore = (z_scores > threshold) | (z_scores < -threshold)

# Mostrar las variables y el número de outliers detectados
print("Número de outliers detectados por Z-score en cada variable:")
print(outliers_zscore.sum())
Número de outliers detectados por Z-score en cada variable:
Passed                           0
Numero de Paginas                8
Cantidad de Palabras            13
Densidad Informacion (%)         6
Fechas Detectadas (Count)       11
Tamaño cuerpo probable           1
Variedad de fuentes              5
Variedad de tamaños              5
Uso de negritas (estimado %)     8
Uso de cursivas (estimado %)     0
Porcentaje Lenguaje Técnico      6
Porcentaje Lenguaje Genérico     6
Cantidad de imágenes            12
Lineas_education                15
Lineas_work_experience          12
Lineas_skills                   13
Lineas_certifications           14
Lineas_achievements             17
Lineas_professional_profile     13
Lineas_languages                13
Lineas_projects                 20
Lineas_publications             14
Lineas_training_courses         15
Lineas_volunteer_work           18
texto_extraido_len              14
Tamaño de fuente más usado       1
dtype: int64

Outliers con rango intercuartilico¶

In [10]:
def detect_outliers_iqr(data, col):
    Q1 = data[col].quantile(0.25)  # Primer cuartil (Q1)
    Q3 = data[col].quantile(0.75)  # Tercer cuartil (Q3)
    IQR = Q3 - Q1  # Rango intercuartílico (IQR)
    lower_bound = Q1 - 1.5 * IQR  # Límite inferior
    upper_bound = Q3 + 1.5 * IQR  # Límite superior
    return data[(data[col] < lower_bound) | (data[col] > upper_bound)]


# Detectar y contar outliers en todas las columnas numéricas
for col in numerical_cols:
    outliers = detect_outliers_iqr(df, col)
    print(f"Outliers detectados en '{col}': {len(outliers)}")
Outliers detectados en 'Passed': 0
Outliers detectados en 'Numero de Paginas': 83
Outliers detectados en 'Cantidad de Palabras': 26
Outliers detectados en 'Densidad Informacion (%)': 29
Outliers detectados en 'Fechas Detectadas (Count)': 31
Outliers detectados en 'Tamaño cuerpo probable': 17
Outliers detectados en 'Variedad de fuentes': 9
Outliers detectados en 'Variedad de tamaños': 42
Outliers detectados en 'Uso de negritas (estimado %)': 10
Outliers detectados en 'Uso de cursivas (estimado %)': 0
Outliers detectados en 'Porcentaje Lenguaje Técnico': 27
Outliers detectados en 'Porcentaje Lenguaje Genérico': 27
Outliers detectados en 'Cantidad de imágenes': 94
Outliers detectados en 'Lineas_education': 57
Outliers detectados en 'Lineas_work_experience': 54
Outliers detectados en 'Lineas_skills': 55
Outliers detectados en 'Lineas_certifications': 90
Outliers detectados en 'Lineas_achievements': 126
Outliers detectados en 'Lineas_professional_profile': 69
Outliers detectados en 'Lineas_languages': 42
Outliers detectados en 'Lineas_projects': 69
Outliers detectados en 'Lineas_publications': 77
Outliers detectados en 'Lineas_training_courses': 67
Outliers detectados en 'Lineas_volunteer_work': 124
Outliers detectados en 'texto_extraido_len': 28
Outliers detectados en 'Tamaño de fuente más usado': 17

Visualizar distribuciones¶

Comparacion de distribuciones por clase de la variable objetivo¶

In [11]:
# Comparar distribuciones por clase de la variable objetivo
target = 'Passed'  # Cambia esto por el nombre de tu variable objetivo

for col in numerical_cols:
    plt.figure(figsize=(10, 5))

    # Separar por clases de la variable objetivo
    if target in df.columns:
        sns.kdeplot(data=df, x=col, hue=target, common_norm=False, fill=True, alpha=0.4)

    # Títulos
    plt.title(f"Distribuciones por clase de '{target}' para '{col}'")
    plt.xlabel(col)
    plt.ylabel("Densidad")

    plt.tight_layout()
    plt.show()
No description has been provided for this image
No description has been provided for this image
No description has been provided for this image
No description has been provided for this image
No description has been provided for this image
No description has been provided for this image
No description has been provided for this image
No description has been provided for this image
No description has been provided for this image
No description has been provided for this image
No description has been provided for this image
No description has been provided for this image
No description has been provided for this image
No description has been provided for this image
No description has been provided for this image
No description has been provided for this image
No description has been provided for this image
No description has been provided for this image
No description has been provided for this image
No description has been provided for this image
No description has been provided for this image
No description has been provided for this image
No description has been provided for this image
No description has been provided for this image
No description has been provided for this image
No description has been provided for this image

Correlacion entre pares variables¶

In [12]:
# Seleccionar solo columnas numéricas
numerical_cols = df.select_dtypes(include=["number"]).columns

# Calcular la matriz de correlación
corr_matrix = df[numerical_cols].corr()

# Mostrar la matriz de correlación como un mapa de calor para identificar relaciones fuertes (opcionales)
plt.figure(figsize=(10, 8))
sns.heatmap(corr_matrix, annot=True, cmap="coolwarm", fmt=".2f")
plt.title("Matriz de correlación de variables numéricas", fontsize=16)
plt.show()

# Seleccionar las correlaciones más altas
threshold = 0.7  # Umbral para considerar correlaciones fuertes
strong_correlations = corr_matrix[(corr_matrix.abs() > threshold) & (corr_matrix.abs() < 1)].unstack().dropna()
strong_correlations = strong_correlations.drop_duplicates().sort_values(ascending=False)

# Mostrar las pares de variables con correlación alta
print("Pares de variables con correlación fuerte:")
print(strong_correlations, "\n")

# Graficar scatterplots para las relaciones con correlaciones fuertes
for (var1, var2) in strong_correlations.index:
    plt.figure(figsize=(8, 6))
    sns.scatterplot(x=df[var1], y=df[var2], alpha=0.7, edgecolor="k")
    plt.title(f"Relación entre '{var1}' y '{var2}' - Correlación: {strong_correlations[(var1, var2)]:.2f}")
    plt.xlabel(var1)
    plt.ylabel(var2)
    plt.grid(True, linestyle="--", alpha=0.5)
    plt.tight_layout()
    plt.show()
No description has been provided for this image
Pares de variables con correlación fuerte:
Cantidad de Palabras  texto_extraido_len    0.873078
dtype: float64 

No description has been provided for this image

Correlación hacia la variable passed¶

In [13]:
# Seleccionar columnas numéricas y la variable objetivo
numerical_cols = df.select_dtypes(include=["number"]).columns
if 'Passed' in numerical_cols:
    numerical_cols = numerical_cols.drop('Passed')  # Excluir 'Passed' de la lista si ya es numérica

# Calcular correlaciones de las variables numéricas con 'Passed'
correlations_with_passed = df[numerical_cols].corrwith(df['Passed']).sort_values(ascending=False)

# Mostrar las correlaciones con 'Passed'
print("Correlaciones entre las variables y 'Passed':")
print(correlations_with_passed, "\n")

# Filtrar las correlaciones fuertes (umbral ajustable)
threshold = 0.3  # Cambiar el umbral según lo que desees considerar como fuerte
strong_correlations = correlations_with_passed[correlations_with_passed.abs() > threshold]

if not strong_correlations.empty:
    print("Variables con correlaciones fuertes hacia 'Passed':")
    print(strong_correlations, "\n")

    # Graficar scatterplots para las correlaciones fuertes
    for var in strong_correlations.index:
        plt.figure(figsize=(8, 6))
        sns.scatterplot(x=df[var], y=df['Passed'], alpha=0.7, edgecolor="k")
        plt.title(f"Relación entre '{var}' y 'Passed' - Correlación: {strong_correlations[var]:.2f}")
        plt.xlabel(var)
        plt.ylabel('Passed')
        plt.grid(True, linestyle="--", alpha=0.5)
        plt.tight_layout()
        plt.show()
else:
    print(f"No hay variables con correlaciones mayores a {threshold} con 'Passed'")
Correlaciones entre las variables y 'Passed':
texto_extraido_len              0.077193
Numero de Paginas               0.066506
Lineas_skills                   0.058905
Lineas_publications             0.056885
Variedad de fuentes             0.040032
Cantidad de Palabras            0.039900
Cantidad de imágenes            0.035832
Fechas Detectadas (Count)       0.035664
Lineas_projects                 0.033511
Lineas_education                0.029298
Lineas_work_experience          0.026319
Lineas_professional_profile     0.023867
Lineas_certifications           0.023342
Lineas_volunteer_work           0.023330
Lineas_achievements             0.015958
Variedad de tamaños             0.009498
Uso de cursivas (estimado %)    0.006785
Porcentaje Lenguaje Genérico    0.005916
Lineas_languages               -0.005255
Porcentaje Lenguaje Técnico    -0.005916
Densidad Informacion (%)       -0.006723
Lineas_training_courses        -0.031485
Tamaño cuerpo probable         -0.040241
Tamaño de fuente más usado     -0.040241
Uso de negritas (estimado %)   -0.067978
dtype: float64 

No hay variables con correlaciones mayores a 0.3 con 'Passed'

Variables binarias vs Passed¶

Transformación de variables para el modelado¶

Transformamos booleanos en números y hacemos Label Encoding para las categóricas

In [14]:
df
Out[14]:
Categoria Original Passed status_procesamiento Numero de Paginas Cantidad de Palabras Densidad Informacion (%) Formato Texto (Lineas) Orden Temporal Fechas Detectadas (Count) Formato Fecha Más Común Fuente principal Tamaño cuerpo probable Legibilidad general Variedad de fuentes Variedad de tamaños Consistencia tamaños fuente Consistencia márgenes (aprox) Uso de negritas (estimado %) Uso de cursivas (estimado %) Uso de colores (texto) Uso de colores (dibujos) Porcentaje Lenguaje Técnico Porcentaje Lenguaje Genérico LinkedIn GitHub Website/Otro Deteccion Foto Perfil Cantidad de imágenes Tiene Elementos Graficos Lineas_education Lineas_work_experience Lineas_skills Lineas_certifications Lineas_achievements Lineas_professional_profile Lineas_languages Lineas_projects Lineas_publications Lineas_training_courses Lineas_volunteer_work Seccion_education Seccion_work_experience Seccion_skills Seccion_certifications Seccion_achievements Seccion_professional_profile Seccion_languages Seccion_projects Seccion_publications Seccion_training_courses Seccion_volunteer_work texto_extraido_len Tamaño de fuente más usado Tamaños fuente detectados
0 Exitoso 1 Completado 2 493 5.71 Viñetas Orden Temporal Detectado 3 Mon YYYY (EN) Garamond-Bold 12 Buena 7 5 Consistente Consistente 34.4 91.7 Sí Sí 3.72 96.28 True False True No se detectaron imágenes candidatas 0 False 6 2 26 0 0 0 0 9 0 0 0 True True True True False True False True True True False 3692 12 [10, 12, 16, 18, 24]
1 Exitoso 1 Completado 1 388 8.09 Viñetas Pocas Fechas 1 MM/YYYY NotoSansZanabazarSquare- 9 Potencialmente Deficiente 1 1 Consistente Consistente 0.0 100.0 No Sí 9.61 90.39 False False True Posible Foto Detectada 9 True 8 12 3 0 0 3 1 0 7 0 0 True True True True False True True True True True False 2703 9 [9]
2 Exitoso 1 Completado 1 378 8.27 Mixto Pocas Fechas 0 Mon YYYY (EN) ArialMT 10 Buena 3 4 Consistente Consistente 21.8 100.0 Sí No 8.58 91.42 False False False No se detectaron imágenes candidatas 0 True 3 38 1 0 0 0 0 0 0 0 0 True True True True False True True True True True True 2761 10 [8, 10, 12, 22]
3 Exitoso 1 Completado 4 656 3.54 Viñetas Orden Temporal Detectado 2 SpaCy DATE (Sin clasificar) Montserrat-Regular 10 Buena 4 12 Inconsistente Inconsistente 16.2 100.0 No Sí 6.67 93.33 False False False Posible Foto Detectada 3 True 25 8 3 0 0 0 17 0 0 18 0 True True True False False True True True True True False 4732 10 [7, 8, 9, 10, 11, 12, 13, 14, 15, 18, 19, 43]
4 Exitoso 1 Completado 3 160 4.71 Viñetas Pocas Fechas 0 YYYY Lato-Regular 10 Buena 6 7 Inconsistente Consistente 31.2 5.2 Sí No 11.29 88.71 True True False Posible Foto Detectada 5 True 0 7 0 0 2 5 8 2 3 1 0 True True True True True True True True True True True 4562 10 [9, 10, 11, 12, 14, 16, 24]
... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ...
630 No Exitoso 0 Completado 6 1372 4.37 Viñetas Pocas Fechas 0 Mon YYYY (EN) Calibri 11 Buena 8 6 Inconsistente Inconsistente 32.7 36.8 Sí Sí 6.72 93.28 False False True Posible Foto Detectada 8 True 6 5 0 6 1 0 3 3 6 6 0 True True True True True True True True True True False 8464 11 [9, 11, 12, 13, 14, 20]
631 No Exitoso 0 Completado 10 3729 7.54 Viñetas Orden Temporal Detectado 3 YYYY Calibri 11 Buena 7 8 Inconsistente Consistente 8.1 5.4 No Sí 2.71 97.29 False False False No se detectaron imágenes candidatas 1 True 0 0 2 4 0 12 0 34 0 5 0 True False True True True True True True True True False 25210 11 [6, 8, 10, 11, 12, 16, 18, 24]
632 No Exitoso 0 Completado 3 899 6.13 Viñetas Pocas Fechas 1 SpaCy DATE (Sin clasificar) OpenSans-Bold 11 Buena 4 6 Inconsistente Consistente 62.7 4.5 No No 5.04 94.96 False False False No se detectaron imágenes candidatas 0 True 5 8 12 0 17 1 1 35 0 0 4 True True True True True True True True True True True 6154 11 [10, 11, 12, 14, 16, 22]
633 No Exitoso 0 Completado 1 185 3.93 Viñetas Orden Temporal Detectado 2 YYYY DidactGothic-Regular 10 Buena 2 4 Consistente Consistente 0.0 100.0 No Sí 6.25 93.75 False False False No se detectaron imágenes candidatas 0 True 0 1 5 0 0 5 5 3 0 2 0 True True True True False True True True True True False 1313 10 [10, 12, 16, 34]
634 No Exitoso 0 Completado 4 534 5.95 Viñetas Pocas Fechas 0 Mes YYYY (ES Comp) ComicSansMS 11 Buena 3 2 Consistente Inconsistente 39.9 0.5 Sí Sí 5.55 94.45 True False False Posible Foto Detectada 2 True 1 0 2 4 1 0 1 1 4 0 0 True True True True True True True True True True True 7693 11 [10, 11]

635 rows × 54 columns

In [15]:
for col in df.select_dtypes(include='bool').columns:
    df[col] = df[col].astype(int)
In [16]:
df
Out[16]:
Categoria Original Passed status_procesamiento Numero de Paginas Cantidad de Palabras Densidad Informacion (%) Formato Texto (Lineas) Orden Temporal Fechas Detectadas (Count) Formato Fecha Más Común Fuente principal Tamaño cuerpo probable Legibilidad general Variedad de fuentes Variedad de tamaños Consistencia tamaños fuente Consistencia márgenes (aprox) Uso de negritas (estimado %) Uso de cursivas (estimado %) Uso de colores (texto) Uso de colores (dibujos) Porcentaje Lenguaje Técnico Porcentaje Lenguaje Genérico LinkedIn GitHub Website/Otro Deteccion Foto Perfil Cantidad de imágenes Tiene Elementos Graficos Lineas_education Lineas_work_experience Lineas_skills Lineas_certifications Lineas_achievements Lineas_professional_profile Lineas_languages Lineas_projects Lineas_publications Lineas_training_courses Lineas_volunteer_work Seccion_education Seccion_work_experience Seccion_skills Seccion_certifications Seccion_achievements Seccion_professional_profile Seccion_languages Seccion_projects Seccion_publications Seccion_training_courses Seccion_volunteer_work texto_extraido_len Tamaño de fuente más usado Tamaños fuente detectados
0 Exitoso 1 Completado 2 493 5.71 Viñetas Orden Temporal Detectado 3 Mon YYYY (EN) Garamond-Bold 12 Buena 7 5 Consistente Consistente 34.4 91.7 Sí Sí 3.72 96.28 1 0 1 No se detectaron imágenes candidatas 0 0 6 2 26 0 0 0 0 9 0 0 0 1 1 1 1 0 1 0 1 1 1 0 3692 12 [10, 12, 16, 18, 24]
1 Exitoso 1 Completado 1 388 8.09 Viñetas Pocas Fechas 1 MM/YYYY NotoSansZanabazarSquare- 9 Potencialmente Deficiente 1 1 Consistente Consistente 0.0 100.0 No Sí 9.61 90.39 0 0 1 Posible Foto Detectada 9 1 8 12 3 0 0 3 1 0 7 0 0 1 1 1 1 0 1 1 1 1 1 0 2703 9 [9]
2 Exitoso 1 Completado 1 378 8.27 Mixto Pocas Fechas 0 Mon YYYY (EN) ArialMT 10 Buena 3 4 Consistente Consistente 21.8 100.0 Sí No 8.58 91.42 0 0 0 No se detectaron imágenes candidatas 0 1 3 38 1 0 0 0 0 0 0 0 0 1 1 1 1 0 1 1 1 1 1 1 2761 10 [8, 10, 12, 22]
3 Exitoso 1 Completado 4 656 3.54 Viñetas Orden Temporal Detectado 2 SpaCy DATE (Sin clasificar) Montserrat-Regular 10 Buena 4 12 Inconsistente Inconsistente 16.2 100.0 No Sí 6.67 93.33 0 0 0 Posible Foto Detectada 3 1 25 8 3 0 0 0 17 0 0 18 0 1 1 1 0 0 1 1 1 1 1 0 4732 10 [7, 8, 9, 10, 11, 12, 13, 14, 15, 18, 19, 43]
4 Exitoso 1 Completado 3 160 4.71 Viñetas Pocas Fechas 0 YYYY Lato-Regular 10 Buena 6 7 Inconsistente Consistente 31.2 5.2 Sí No 11.29 88.71 1 1 0 Posible Foto Detectada 5 1 0 7 0 0 2 5 8 2 3 1 0 1 1 1 1 1 1 1 1 1 1 1 4562 10 [9, 10, 11, 12, 14, 16, 24]
... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ...
630 No Exitoso 0 Completado 6 1372 4.37 Viñetas Pocas Fechas 0 Mon YYYY (EN) Calibri 11 Buena 8 6 Inconsistente Inconsistente 32.7 36.8 Sí Sí 6.72 93.28 0 0 1 Posible Foto Detectada 8 1 6 5 0 6 1 0 3 3 6 6 0 1 1 1 1 1 1 1 1 1 1 0 8464 11 [9, 11, 12, 13, 14, 20]
631 No Exitoso 0 Completado 10 3729 7.54 Viñetas Orden Temporal Detectado 3 YYYY Calibri 11 Buena 7 8 Inconsistente Consistente 8.1 5.4 No Sí 2.71 97.29 0 0 0 No se detectaron imágenes candidatas 1 1 0 0 2 4 0 12 0 34 0 5 0 1 0 1 1 1 1 1 1 1 1 0 25210 11 [6, 8, 10, 11, 12, 16, 18, 24]
632 No Exitoso 0 Completado 3 899 6.13 Viñetas Pocas Fechas 1 SpaCy DATE (Sin clasificar) OpenSans-Bold 11 Buena 4 6 Inconsistente Consistente 62.7 4.5 No No 5.04 94.96 0 0 0 No se detectaron imágenes candidatas 0 1 5 8 12 0 17 1 1 35 0 0 4 1 1 1 1 1 1 1 1 1 1 1 6154 11 [10, 11, 12, 14, 16, 22]
633 No Exitoso 0 Completado 1 185 3.93 Viñetas Orden Temporal Detectado 2 YYYY DidactGothic-Regular 10 Buena 2 4 Consistente Consistente 0.0 100.0 No Sí 6.25 93.75 0 0 0 No se detectaron imágenes candidatas 0 1 0 1 5 0 0 5 5 3 0 2 0 1 1 1 1 0 1 1 1 1 1 0 1313 10 [10, 12, 16, 34]
634 No Exitoso 0 Completado 4 534 5.95 Viñetas Pocas Fechas 0 Mes YYYY (ES Comp) ComicSansMS 11 Buena 3 2 Consistente Inconsistente 39.9 0.5 Sí Sí 5.55 94.45 1 0 0 Posible Foto Detectada 2 1 1 0 2 4 1 0 1 1 4 0 0 1 1 1 1 1 1 1 1 1 1 1 7693 11 [10, 11]

635 rows × 54 columns

Eliminar filas que no pudieron ser procesadas¶

In [17]:
valor_a_eliminar = 'Advertencia: No se extrajo texto'

# 2. Crea una condición booleana: True para las filas que quieres MANTENER
#    (Es decir, donde 'status_procesamiento' es DIFERENTE al valor a eliminar)
condicion = df['status_procesamiento'] != valor_a_eliminar

df = df[condicion]
In [18]:
df
Out[18]:
Categoria Original Passed status_procesamiento Numero de Paginas Cantidad de Palabras Densidad Informacion (%) Formato Texto (Lineas) Orden Temporal Fechas Detectadas (Count) Formato Fecha Más Común Fuente principal Tamaño cuerpo probable Legibilidad general Variedad de fuentes Variedad de tamaños Consistencia tamaños fuente Consistencia márgenes (aprox) Uso de negritas (estimado %) Uso de cursivas (estimado %) Uso de colores (texto) Uso de colores (dibujos) Porcentaje Lenguaje Técnico Porcentaje Lenguaje Genérico LinkedIn GitHub Website/Otro Deteccion Foto Perfil Cantidad de imágenes Tiene Elementos Graficos Lineas_education Lineas_work_experience Lineas_skills Lineas_certifications Lineas_achievements Lineas_professional_profile Lineas_languages Lineas_projects Lineas_publications Lineas_training_courses Lineas_volunteer_work Seccion_education Seccion_work_experience Seccion_skills Seccion_certifications Seccion_achievements Seccion_professional_profile Seccion_languages Seccion_projects Seccion_publications Seccion_training_courses Seccion_volunteer_work texto_extraido_len Tamaño de fuente más usado Tamaños fuente detectados
0 Exitoso 1 Completado 2 493 5.71 Viñetas Orden Temporal Detectado 3 Mon YYYY (EN) Garamond-Bold 12 Buena 7 5 Consistente Consistente 34.4 91.7 Sí Sí 3.72 96.28 1 0 1 No se detectaron imágenes candidatas 0 0 6 2 26 0 0 0 0 9 0 0 0 1 1 1 1 0 1 0 1 1 1 0 3692 12 [10, 12, 16, 18, 24]
1 Exitoso 1 Completado 1 388 8.09 Viñetas Pocas Fechas 1 MM/YYYY NotoSansZanabazarSquare- 9 Potencialmente Deficiente 1 1 Consistente Consistente 0.0 100.0 No Sí 9.61 90.39 0 0 1 Posible Foto Detectada 9 1 8 12 3 0 0 3 1 0 7 0 0 1 1 1 1 0 1 1 1 1 1 0 2703 9 [9]
2 Exitoso 1 Completado 1 378 8.27 Mixto Pocas Fechas 0 Mon YYYY (EN) ArialMT 10 Buena 3 4 Consistente Consistente 21.8 100.0 Sí No 8.58 91.42 0 0 0 No se detectaron imágenes candidatas 0 1 3 38 1 0 0 0 0 0 0 0 0 1 1 1 1 0 1 1 1 1 1 1 2761 10 [8, 10, 12, 22]
3 Exitoso 1 Completado 4 656 3.54 Viñetas Orden Temporal Detectado 2 SpaCy DATE (Sin clasificar) Montserrat-Regular 10 Buena 4 12 Inconsistente Inconsistente 16.2 100.0 No Sí 6.67 93.33 0 0 0 Posible Foto Detectada 3 1 25 8 3 0 0 0 17 0 0 18 0 1 1 1 0 0 1 1 1 1 1 0 4732 10 [7, 8, 9, 10, 11, 12, 13, 14, 15, 18, 19, 43]
4 Exitoso 1 Completado 3 160 4.71 Viñetas Pocas Fechas 0 YYYY Lato-Regular 10 Buena 6 7 Inconsistente Consistente 31.2 5.2 Sí No 11.29 88.71 1 1 0 Posible Foto Detectada 5 1 0 7 0 0 2 5 8 2 3 1 0 1 1 1 1 1 1 1 1 1 1 1 4562 10 [9, 10, 11, 12, 14, 16, 24]
... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ...
630 No Exitoso 0 Completado 6 1372 4.37 Viñetas Pocas Fechas 0 Mon YYYY (EN) Calibri 11 Buena 8 6 Inconsistente Inconsistente 32.7 36.8 Sí Sí 6.72 93.28 0 0 1 Posible Foto Detectada 8 1 6 5 0 6 1 0 3 3 6 6 0 1 1 1 1 1 1 1 1 1 1 0 8464 11 [9, 11, 12, 13, 14, 20]
631 No Exitoso 0 Completado 10 3729 7.54 Viñetas Orden Temporal Detectado 3 YYYY Calibri 11 Buena 7 8 Inconsistente Consistente 8.1 5.4 No Sí 2.71 97.29 0 0 0 No se detectaron imágenes candidatas 1 1 0 0 2 4 0 12 0 34 0 5 0 1 0 1 1 1 1 1 1 1 1 0 25210 11 [6, 8, 10, 11, 12, 16, 18, 24]
632 No Exitoso 0 Completado 3 899 6.13 Viñetas Pocas Fechas 1 SpaCy DATE (Sin clasificar) OpenSans-Bold 11 Buena 4 6 Inconsistente Consistente 62.7 4.5 No No 5.04 94.96 0 0 0 No se detectaron imágenes candidatas 0 1 5 8 12 0 17 1 1 35 0 0 4 1 1 1 1 1 1 1 1 1 1 1 6154 11 [10, 11, 12, 14, 16, 22]
633 No Exitoso 0 Completado 1 185 3.93 Viñetas Orden Temporal Detectado 2 YYYY DidactGothic-Regular 10 Buena 2 4 Consistente Consistente 0.0 100.0 No Sí 6.25 93.75 0 0 0 No se detectaron imágenes candidatas 0 1 0 1 5 0 0 5 5 3 0 2 0 1 1 1 1 0 1 1 1 1 1 0 1313 10 [10, 12, 16, 34]
634 No Exitoso 0 Completado 4 534 5.95 Viñetas Pocas Fechas 0 Mes YYYY (ES Comp) ComicSansMS 11 Buena 3 2 Consistente Inconsistente 39.9 0.5 Sí Sí 5.55 94.45 1 0 0 Posible Foto Detectada 2 1 1 0 2 4 1 0 1 1 4 0 0 1 1 1 1 1 1 1 1 1 1 1 7693 11 [10, 11]

626 rows × 54 columns

Agrupar fuentes entre más comunes y otras para facilitar la lectura¶

In [19]:
# 1. Define la lista de fuentes que quieres mantener
fuentes_principales = ['ArialMT', 'Calibri', 'Tahoma', 'Roboto-Regular',
                       'Lato-Regular', 'OpenSans-Regular', 'Ninguna']

# 2. Crea una condición booleana: True para las filas cuya fuente NO ESTÁ en la lista
#    El símbolo '~' niega el resultado de isin()
condicion_otras = ~df['Fuente principal'].isin(fuentes_principales)

# 3. Usa .loc para seleccionar esas filas (condicion_otras) y la columna 'Fuente principal',
#    y asígnales el nuevo valor 'Otra'.
#    ¡Esto modifica el DataFrame original directamente!
#    Si no quieres modificar el original, haz una copia antes: df_copia = df.copy()
df.loc[condicion_otras, 'Fuente principal'] = 'Otra'

df
Out[19]:
Categoria Original Passed status_procesamiento Numero de Paginas Cantidad de Palabras Densidad Informacion (%) Formato Texto (Lineas) Orden Temporal Fechas Detectadas (Count) Formato Fecha Más Común Fuente principal Tamaño cuerpo probable Legibilidad general Variedad de fuentes Variedad de tamaños Consistencia tamaños fuente Consistencia márgenes (aprox) Uso de negritas (estimado %) Uso de cursivas (estimado %) Uso de colores (texto) Uso de colores (dibujos) Porcentaje Lenguaje Técnico Porcentaje Lenguaje Genérico LinkedIn GitHub Website/Otro Deteccion Foto Perfil Cantidad de imágenes Tiene Elementos Graficos Lineas_education Lineas_work_experience Lineas_skills Lineas_certifications Lineas_achievements Lineas_professional_profile Lineas_languages Lineas_projects Lineas_publications Lineas_training_courses Lineas_volunteer_work Seccion_education Seccion_work_experience Seccion_skills Seccion_certifications Seccion_achievements Seccion_professional_profile Seccion_languages Seccion_projects Seccion_publications Seccion_training_courses Seccion_volunteer_work texto_extraido_len Tamaño de fuente más usado Tamaños fuente detectados
0 Exitoso 1 Completado 2 493 5.71 Viñetas Orden Temporal Detectado 3 Mon YYYY (EN) Otra 12 Buena 7 5 Consistente Consistente 34.4 91.7 Sí Sí 3.72 96.28 1 0 1 No se detectaron imágenes candidatas 0 0 6 2 26 0 0 0 0 9 0 0 0 1 1 1 1 0 1 0 1 1 1 0 3692 12 [10, 12, 16, 18, 24]
1 Exitoso 1 Completado 1 388 8.09 Viñetas Pocas Fechas 1 MM/YYYY Otra 9 Potencialmente Deficiente 1 1 Consistente Consistente 0.0 100.0 No Sí 9.61 90.39 0 0 1 Posible Foto Detectada 9 1 8 12 3 0 0 3 1 0 7 0 0 1 1 1 1 0 1 1 1 1 1 0 2703 9 [9]
2 Exitoso 1 Completado 1 378 8.27 Mixto Pocas Fechas 0 Mon YYYY (EN) ArialMT 10 Buena 3 4 Consistente Consistente 21.8 100.0 Sí No 8.58 91.42 0 0 0 No se detectaron imágenes candidatas 0 1 3 38 1 0 0 0 0 0 0 0 0 1 1 1 1 0 1 1 1 1 1 1 2761 10 [8, 10, 12, 22]
3 Exitoso 1 Completado 4 656 3.54 Viñetas Orden Temporal Detectado 2 SpaCy DATE (Sin clasificar) Otra 10 Buena 4 12 Inconsistente Inconsistente 16.2 100.0 No Sí 6.67 93.33 0 0 0 Posible Foto Detectada 3 1 25 8 3 0 0 0 17 0 0 18 0 1 1 1 0 0 1 1 1 1 1 0 4732 10 [7, 8, 9, 10, 11, 12, 13, 14, 15, 18, 19, 43]
4 Exitoso 1 Completado 3 160 4.71 Viñetas Pocas Fechas 0 YYYY Lato-Regular 10 Buena 6 7 Inconsistente Consistente 31.2 5.2 Sí No 11.29 88.71 1 1 0 Posible Foto Detectada 5 1 0 7 0 0 2 5 8 2 3 1 0 1 1 1 1 1 1 1 1 1 1 1 4562 10 [9, 10, 11, 12, 14, 16, 24]
... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ...
630 No Exitoso 0 Completado 6 1372 4.37 Viñetas Pocas Fechas 0 Mon YYYY (EN) Calibri 11 Buena 8 6 Inconsistente Inconsistente 32.7 36.8 Sí Sí 6.72 93.28 0 0 1 Posible Foto Detectada 8 1 6 5 0 6 1 0 3 3 6 6 0 1 1 1 1 1 1 1 1 1 1 0 8464 11 [9, 11, 12, 13, 14, 20]
631 No Exitoso 0 Completado 10 3729 7.54 Viñetas Orden Temporal Detectado 3 YYYY Calibri 11 Buena 7 8 Inconsistente Consistente 8.1 5.4 No Sí 2.71 97.29 0 0 0 No se detectaron imágenes candidatas 1 1 0 0 2 4 0 12 0 34 0 5 0 1 0 1 1 1 1 1 1 1 1 0 25210 11 [6, 8, 10, 11, 12, 16, 18, 24]
632 No Exitoso 0 Completado 3 899 6.13 Viñetas Pocas Fechas 1 SpaCy DATE (Sin clasificar) Otra 11 Buena 4 6 Inconsistente Consistente 62.7 4.5 No No 5.04 94.96 0 0 0 No se detectaron imágenes candidatas 0 1 5 8 12 0 17 1 1 35 0 0 4 1 1 1 1 1 1 1 1 1 1 1 6154 11 [10, 11, 12, 14, 16, 22]
633 No Exitoso 0 Completado 1 185 3.93 Viñetas Orden Temporal Detectado 2 YYYY Otra 10 Buena 2 4 Consistente Consistente 0.0 100.0 No Sí 6.25 93.75 0 0 0 No se detectaron imágenes candidatas 0 1 0 1 5 0 0 5 5 3 0 2 0 1 1 1 1 0 1 1 1 1 1 0 1313 10 [10, 12, 16, 34]
634 No Exitoso 0 Completado 4 534 5.95 Viñetas Pocas Fechas 0 Mes YYYY (ES Comp) Otra 11 Buena 3 2 Consistente Inconsistente 39.9 0.5 Sí Sí 5.55 94.45 1 0 0 Posible Foto Detectada 2 1 1 0 2 4 1 0 1 1 4 0 0 1 1 1 1 1 1 1 1 1 1 1 7693 11 [10, 11]

626 rows × 54 columns

Transformar la variable 'Tamaño de fuente detectados' por 'Promedio tamaño de fuente, para más fácil lectura del módelo.¶

In [20]:
def convertir_a_lista(valor):
    """Intenta convertir un valor a lista usando ast.literal_eval."""
    if isinstance(valor, str): # Solo procesa si es un string
        try:
            # Intenta evaluar el string como una estructura literal de Python (lista)
            return ast.literal_eval(valor)
        except (ValueError, SyntaxError):
            # Si no se puede evaluar (no es un string tipo lista válido), devuelve None o NaN
            return np.nan # O podrías devolver una lista vacía: []
    elif isinstance(valor, list):
         # Si ya es una lista, devuélvela tal cual
        return valor
    else:
        # Si es None, NaN u otro tipo, devuelve NaN
        return np.nan

# Aplica la función de conversión a la columna
# Esto sobreescribe la columna original con listas reales (o NaN si falla)
df['Tamaños fuente detectados'] = df['Tamaños fuente detectados'].apply(convertir_a_lista)

# --- Ahora, vuelve a intentar calcular el promedio ---

def calcular_promedio_lista(lista):
    # Verifica si es una lista y si no está vacía
    if isinstance(lista, list) and len(lista) > 0:
        # Asegurarse que todos los elementos son numéricos (opcional pero más robusto)
        elementos_numericos = [x for x in lista if isinstance(x, (int, float))]
        if len(elementos_numericos) > 0:
             return sum(elementos_numericos) / len(elementos_numericos)
        else:
             return np.nan # Si la lista no tenía números
    return np.nan # Si no es lista, está vacía, o no tenía números


# Aplica la función de promedio (ahora sobre las listas reales)
df['Promedio tamaño fuente'] = df['Tamaños fuente detectados'].apply(calcular_promedio_lista)

#Eliminar nulos
df.dropna()
Out[20]:
Categoria Original Passed status_procesamiento Numero de Paginas Cantidad de Palabras Densidad Informacion (%) Formato Texto (Lineas) Orden Temporal Fechas Detectadas (Count) Formato Fecha Más Común Fuente principal Tamaño cuerpo probable Legibilidad general Variedad de fuentes Variedad de tamaños Consistencia tamaños fuente Consistencia márgenes (aprox) Uso de negritas (estimado %) Uso de cursivas (estimado %) Uso de colores (texto) Uso de colores (dibujos) Porcentaje Lenguaje Técnico Porcentaje Lenguaje Genérico LinkedIn GitHub Website/Otro Deteccion Foto Perfil Cantidad de imágenes Tiene Elementos Graficos Lineas_education Lineas_work_experience Lineas_skills Lineas_certifications Lineas_achievements Lineas_professional_profile Lineas_languages Lineas_projects Lineas_publications Lineas_training_courses Lineas_volunteer_work Seccion_education Seccion_work_experience Seccion_skills Seccion_certifications Seccion_achievements Seccion_professional_profile Seccion_languages Seccion_projects Seccion_publications Seccion_training_courses Seccion_volunteer_work texto_extraido_len Tamaño de fuente más usado Tamaños fuente detectados Promedio tamaño fuente
0 Exitoso 1 Completado 2 493 5.71 Viñetas Orden Temporal Detectado 3 Mon YYYY (EN) Otra 12 Buena 7 5 Consistente Consistente 34.4 91.7 Sí Sí 3.72 96.28 1 0 1 No se detectaron imágenes candidatas 0 0 6 2 26 0 0 0 0 9 0 0 0 1 1 1 1 0 1 0 1 1 1 0 3692 12 [10, 12, 16, 18, 24] 16.000000
1 Exitoso 1 Completado 1 388 8.09 Viñetas Pocas Fechas 1 MM/YYYY Otra 9 Potencialmente Deficiente 1 1 Consistente Consistente 0.0 100.0 No Sí 9.61 90.39 0 0 1 Posible Foto Detectada 9 1 8 12 3 0 0 3 1 0 7 0 0 1 1 1 1 0 1 1 1 1 1 0 2703 9 [9] 9.000000
2 Exitoso 1 Completado 1 378 8.27 Mixto Pocas Fechas 0 Mon YYYY (EN) ArialMT 10 Buena 3 4 Consistente Consistente 21.8 100.0 Sí No 8.58 91.42 0 0 0 No se detectaron imágenes candidatas 0 1 3 38 1 0 0 0 0 0 0 0 0 1 1 1 1 0 1 1 1 1 1 1 2761 10 [8, 10, 12, 22] 13.000000
3 Exitoso 1 Completado 4 656 3.54 Viñetas Orden Temporal Detectado 2 SpaCy DATE (Sin clasificar) Otra 10 Buena 4 12 Inconsistente Inconsistente 16.2 100.0 No Sí 6.67 93.33 0 0 0 Posible Foto Detectada 3 1 25 8 3 0 0 0 17 0 0 18 0 1 1 1 0 0 1 1 1 1 1 0 4732 10 [7, 8, 9, 10, 11, 12, 13, 14, 15, 18, 19, 43] 14.916667
4 Exitoso 1 Completado 3 160 4.71 Viñetas Pocas Fechas 0 YYYY Lato-Regular 10 Buena 6 7 Inconsistente Consistente 31.2 5.2 Sí No 11.29 88.71 1 1 0 Posible Foto Detectada 5 1 0 7 0 0 2 5 8 2 3 1 0 1 1 1 1 1 1 1 1 1 1 1 4562 10 [9, 10, 11, 12, 14, 16, 24] 13.714286
... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ...
630 No Exitoso 0 Completado 6 1372 4.37 Viñetas Pocas Fechas 0 Mon YYYY (EN) Calibri 11 Buena 8 6 Inconsistente Inconsistente 32.7 36.8 Sí Sí 6.72 93.28 0 0 1 Posible Foto Detectada 8 1 6 5 0 6 1 0 3 3 6 6 0 1 1 1 1 1 1 1 1 1 1 0 8464 11 [9, 11, 12, 13, 14, 20] 13.166667
631 No Exitoso 0 Completado 10 3729 7.54 Viñetas Orden Temporal Detectado 3 YYYY Calibri 11 Buena 7 8 Inconsistente Consistente 8.1 5.4 No Sí 2.71 97.29 0 0 0 No se detectaron imágenes candidatas 1 1 0 0 2 4 0 12 0 34 0 5 0 1 0 1 1 1 1 1 1 1 1 0 25210 11 [6, 8, 10, 11, 12, 16, 18, 24] 13.125000
632 No Exitoso 0 Completado 3 899 6.13 Viñetas Pocas Fechas 1 SpaCy DATE (Sin clasificar) Otra 11 Buena 4 6 Inconsistente Consistente 62.7 4.5 No No 5.04 94.96 0 0 0 No se detectaron imágenes candidatas 0 1 5 8 12 0 17 1 1 35 0 0 4 1 1 1 1 1 1 1 1 1 1 1 6154 11 [10, 11, 12, 14, 16, 22] 14.166667
633 No Exitoso 0 Completado 1 185 3.93 Viñetas Orden Temporal Detectado 2 YYYY Otra 10 Buena 2 4 Consistente Consistente 0.0 100.0 No Sí 6.25 93.75 0 0 0 No se detectaron imágenes candidatas 0 1 0 1 5 0 0 5 5 3 0 2 0 1 1 1 1 0 1 1 1 1 1 0 1313 10 [10, 12, 16, 34] 18.000000
634 No Exitoso 0 Completado 4 534 5.95 Viñetas Pocas Fechas 0 Mes YYYY (ES Comp) Otra 11 Buena 3 2 Consistente Inconsistente 39.9 0.5 Sí Sí 5.55 94.45 1 0 0 Posible Foto Detectada 2 1 1 0 2 4 1 0 1 1 4 0 0 1 1 1 1 1 1 1 1 1 1 1 7693 11 [10, 11] 10.500000

614 rows × 55 columns

In [21]:
df= df.dropna()

Drop columns que no son útiles para el modelo o ya transformadas en otra variable¶

In [22]:
df = df.drop(columns=["Categoria Original","status_procesamiento", "Tamaños fuente detectados", ], errors="ignore")
In [23]:
df
Out[23]:
Passed Numero de Paginas Cantidad de Palabras Densidad Informacion (%) Formato Texto (Lineas) Orden Temporal Fechas Detectadas (Count) Formato Fecha Más Común Fuente principal Tamaño cuerpo probable Legibilidad general Variedad de fuentes Variedad de tamaños Consistencia tamaños fuente Consistencia márgenes (aprox) Uso de negritas (estimado %) Uso de cursivas (estimado %) Uso de colores (texto) Uso de colores (dibujos) Porcentaje Lenguaje Técnico Porcentaje Lenguaje Genérico LinkedIn GitHub Website/Otro Deteccion Foto Perfil Cantidad de imágenes Tiene Elementos Graficos Lineas_education Lineas_work_experience Lineas_skills Lineas_certifications Lineas_achievements Lineas_professional_profile Lineas_languages Lineas_projects Lineas_publications Lineas_training_courses Lineas_volunteer_work Seccion_education Seccion_work_experience Seccion_skills Seccion_certifications Seccion_achievements Seccion_professional_profile Seccion_languages Seccion_projects Seccion_publications Seccion_training_courses Seccion_volunteer_work texto_extraido_len Tamaño de fuente más usado Promedio tamaño fuente
0 1 2 493 5.71 Viñetas Orden Temporal Detectado 3 Mon YYYY (EN) Otra 12 Buena 7 5 Consistente Consistente 34.4 91.7 Sí Sí 3.72 96.28 1 0 1 No se detectaron imágenes candidatas 0 0 6 2 26 0 0 0 0 9 0 0 0 1 1 1 1 0 1 0 1 1 1 0 3692 12 16.000000
1 1 1 388 8.09 Viñetas Pocas Fechas 1 MM/YYYY Otra 9 Potencialmente Deficiente 1 1 Consistente Consistente 0.0 100.0 No Sí 9.61 90.39 0 0 1 Posible Foto Detectada 9 1 8 12 3 0 0 3 1 0 7 0 0 1 1 1 1 0 1 1 1 1 1 0 2703 9 9.000000
2 1 1 378 8.27 Mixto Pocas Fechas 0 Mon YYYY (EN) ArialMT 10 Buena 3 4 Consistente Consistente 21.8 100.0 Sí No 8.58 91.42 0 0 0 No se detectaron imágenes candidatas 0 1 3 38 1 0 0 0 0 0 0 0 0 1 1 1 1 0 1 1 1 1 1 1 2761 10 13.000000
3 1 4 656 3.54 Viñetas Orden Temporal Detectado 2 SpaCy DATE (Sin clasificar) Otra 10 Buena 4 12 Inconsistente Inconsistente 16.2 100.0 No Sí 6.67 93.33 0 0 0 Posible Foto Detectada 3 1 25 8 3 0 0 0 17 0 0 18 0 1 1 1 0 0 1 1 1 1 1 0 4732 10 14.916667
4 1 3 160 4.71 Viñetas Pocas Fechas 0 YYYY Lato-Regular 10 Buena 6 7 Inconsistente Consistente 31.2 5.2 Sí No 11.29 88.71 1 1 0 Posible Foto Detectada 5 1 0 7 0 0 2 5 8 2 3 1 0 1 1 1 1 1 1 1 1 1 1 1 4562 10 13.714286
... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ...
630 0 6 1372 4.37 Viñetas Pocas Fechas 0 Mon YYYY (EN) Calibri 11 Buena 8 6 Inconsistente Inconsistente 32.7 36.8 Sí Sí 6.72 93.28 0 0 1 Posible Foto Detectada 8 1 6 5 0 6 1 0 3 3 6 6 0 1 1 1 1 1 1 1 1 1 1 0 8464 11 13.166667
631 0 10 3729 7.54 Viñetas Orden Temporal Detectado 3 YYYY Calibri 11 Buena 7 8 Inconsistente Consistente 8.1 5.4 No Sí 2.71 97.29 0 0 0 No se detectaron imágenes candidatas 1 1 0 0 2 4 0 12 0 34 0 5 0 1 0 1 1 1 1 1 1 1 1 0 25210 11 13.125000
632 0 3 899 6.13 Viñetas Pocas Fechas 1 SpaCy DATE (Sin clasificar) Otra 11 Buena 4 6 Inconsistente Consistente 62.7 4.5 No No 5.04 94.96 0 0 0 No se detectaron imágenes candidatas 0 1 5 8 12 0 17 1 1 35 0 0 4 1 1 1 1 1 1 1 1 1 1 1 6154 11 14.166667
633 0 1 185 3.93 Viñetas Orden Temporal Detectado 2 YYYY Otra 10 Buena 2 4 Consistente Consistente 0.0 100.0 No Sí 6.25 93.75 0 0 0 No se detectaron imágenes candidatas 0 1 0 1 5 0 0 5 5 3 0 2 0 1 1 1 1 0 1 1 1 1 1 0 1313 10 18.000000
634 0 4 534 5.95 Viñetas Pocas Fechas 0 Mes YYYY (ES Comp) Otra 11 Buena 3 2 Consistente Inconsistente 39.9 0.5 Sí Sí 5.55 94.45 1 0 0 Posible Foto Detectada 2 1 1 0 2 4 1 0 1 1 4 0 0 1 1 1 1 1 1 1 1 1 1 1 7693 11 10.500000

614 rows × 52 columns

Encoding de variables categóricas¶

In [24]:
df = pd.get_dummies(df)
for col in df.select_dtypes(include='bool').columns:
    df[col] = df[col].astype(int)
In [25]:
df
Out[25]:
Passed Numero de Paginas Cantidad de Palabras Densidad Informacion (%) Fechas Detectadas (Count) Tamaño cuerpo probable Variedad de fuentes Variedad de tamaños Uso de negritas (estimado %) Uso de cursivas (estimado %) Porcentaje Lenguaje Técnico Porcentaje Lenguaje Genérico LinkedIn GitHub Website/Otro Cantidad de imágenes Tiene Elementos Graficos Lineas_education Lineas_work_experience Lineas_skills Lineas_certifications Lineas_achievements Lineas_professional_profile Lineas_languages Lineas_projects Lineas_publications Lineas_training_courses Lineas_volunteer_work Seccion_education Seccion_work_experience Seccion_skills Seccion_certifications Seccion_achievements Seccion_professional_profile Seccion_languages Seccion_projects Seccion_publications Seccion_training_courses Seccion_volunteer_work texto_extraido_len Tamaño de fuente más usado Promedio tamaño fuente Formato Texto (Lineas)_Mixto Formato Texto (Lineas)_Párrafos Formato Texto (Lineas)_Viñetas Orden Temporal_Orden Temporal Detectado Orden Temporal_Pocas Fechas Formato Fecha Más Común_DD/MM/YYYY Formato Fecha Más Común_MM-YYYY Formato Fecha Más Común_MM/YYYY Formato Fecha Más Común_Mes YYYY (ES Comp) Formato Fecha Más Común_Mon YYYY (EN) Formato Fecha Más Común_Month YYYY (EN) Formato Fecha Más Común_Rango YYYY-YYYY Formato Fecha Más Común_SpaCy DATE (Sin clasificar) Formato Fecha Más Común_YYYY Formato Fecha Más Común_YYYY (SpaCy) Fuente principal_ArialMT Fuente principal_Calibri Fuente principal_Lato-Regular Fuente principal_OpenSans-Regular Fuente principal_Otra Fuente principal_Roboto-Regular Fuente principal_Tahoma Legibilidad general_Buena Legibilidad general_Potencialmente Deficiente Consistencia tamaños fuente_Consistente Consistencia tamaños fuente_Inconsistente Consistencia márgenes (aprox)_Consistente Consistencia márgenes (aprox)_Inconsistente Uso de colores (texto)_No Uso de colores (texto)_Sí Uso de colores (dibujos)_No Uso de colores (dibujos)_Sí Deteccion Foto Perfil_No se detectaron imágenes candidatas Deteccion Foto Perfil_Posible Foto Detectada
0 1 2 493 5.71 3 12 7 5 34.4 91.7 3.72 96.28 1 0 1 0 0 6 2 26 0 0 0 0 9 0 0 0 1 1 1 1 0 1 0 1 1 1 0 3692 12 16.000000 0 0 1 1 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 1 0 0 1 0 1 0 1 0 0 1 0 1 1 0
1 1 1 388 8.09 1 9 1 1 0.0 100.0 9.61 90.39 0 0 1 9 1 8 12 3 0 0 3 1 0 7 0 0 1 1 1 1 0 1 1 1 1 1 0 2703 9 9.000000 0 0 1 0 1 0 0 1 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 1 1 0 1 0 1 0 0 1 0 1
2 1 1 378 8.27 0 10 3 4 21.8 100.0 8.58 91.42 0 0 0 0 1 3 38 1 0 0 0 0 0 0 0 0 1 1 1 1 0 1 1 1 1 1 1 2761 10 13.000000 1 0 0 0 1 0 0 0 0 1 0 0 0 0 0 1 0 0 0 0 0 0 1 0 1 0 1 0 0 1 1 0 1 0
3 1 4 656 3.54 2 10 4 12 16.2 100.0 6.67 93.33 0 0 0 3 1 25 8 3 0 0 0 17 0 0 18 0 1 1 1 0 0 1 1 1 1 1 0 4732 10 14.916667 0 0 1 1 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 1 0 0 1 0 0 1 0 1 1 0 0 1 0 1
4 1 3 160 4.71 0 10 6 7 31.2 5.2 11.29 88.71 1 1 0 5 1 0 7 0 0 2 5 8 2 3 1 0 1 1 1 1 1 1 1 1 1 1 1 4562 10 13.714286 0 0 1 0 1 0 0 0 0 0 0 0 0 1 0 0 0 1 0 0 0 0 1 0 0 1 1 0 0 1 1 0 0 1
... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ...
630 0 6 1372 4.37 0 11 8 6 32.7 36.8 6.72 93.28 0 0 1 8 1 6 5 0 6 1 0 3 3 6 6 0 1 1 1 1 1 1 1 1 1 1 0 8464 11 13.166667 0 0 1 0 1 0 0 0 0 1 0 0 0 0 0 0 1 0 0 0 0 0 1 0 0 1 0 1 0 1 0 1 0 1
631 0 10 3729 7.54 3 11 7 8 8.1 5.4 2.71 97.29 0 0 0 1 1 0 0 2 4 0 12 0 34 0 5 0 1 0 1 1 1 1 1 1 1 1 0 25210 11 13.125000 0 0 1 1 0 0 0 0 0 0 0 0 0 1 0 0 1 0 0 0 0 0 1 0 0 1 1 0 1 0 0 1 1 0
632 0 3 899 6.13 1 11 4 6 62.7 4.5 5.04 94.96 0 0 0 0 1 5 8 12 0 17 1 1 35 0 0 4 1 1 1 1 1 1 1 1 1 1 1 6154 11 14.166667 0 0 1 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 1 0 0 1 0 0 1 1 0 1 0 1 0 1 0
633 0 1 185 3.93 2 10 2 4 0.0 100.0 6.25 93.75 0 0 0 0 1 0 1 5 0 0 5 5 3 0 2 0 1 1 1 1 0 1 1 1 1 1 0 1313 10 18.000000 0 0 1 1 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 1 0 0 1 0 1 0 1 0 1 0 0 1 1 0
634 0 4 534 5.95 0 11 3 2 39.9 0.5 5.55 94.45 1 0 0 2 1 1 0 2 4 1 0 1 1 4 0 0 1 1 1 1 1 1 1 1 1 1 1 7693 11 10.500000 0 0 1 0 1 0 0 0 1 0 0 0 0 0 0 0 0 0 0 1 0 0 1 0 1 0 0 1 0 1 0 1 0 1

614 rows × 76 columns

Número de secciones completas¶

In [26]:
secciones = ["Seccion_professional_profile", "Seccion_education", "Seccion_work_experience", "Seccion_skills",
             "Seccion_certifications", "Seccion_achievements", "Seccion_languages", "Seccion_projects",
             "Seccion_training_courses", "Seccion_volunteer_work"]

df["secciones_completas"] = df[secciones].apply(lambda row: (row > 0).sum(), axis=1)
In [27]:
df
Out[27]:
Passed Numero de Paginas Cantidad de Palabras Densidad Informacion (%) Fechas Detectadas (Count) Tamaño cuerpo probable Variedad de fuentes Variedad de tamaños Uso de negritas (estimado %) Uso de cursivas (estimado %) Porcentaje Lenguaje Técnico Porcentaje Lenguaje Genérico LinkedIn GitHub Website/Otro Cantidad de imágenes Tiene Elementos Graficos Lineas_education Lineas_work_experience Lineas_skills Lineas_certifications Lineas_achievements Lineas_professional_profile Lineas_languages Lineas_projects Lineas_publications Lineas_training_courses Lineas_volunteer_work Seccion_education Seccion_work_experience Seccion_skills Seccion_certifications Seccion_achievements Seccion_professional_profile Seccion_languages Seccion_projects Seccion_publications Seccion_training_courses Seccion_volunteer_work texto_extraido_len Tamaño de fuente más usado Promedio tamaño fuente Formato Texto (Lineas)_Mixto Formato Texto (Lineas)_Párrafos Formato Texto (Lineas)_Viñetas Orden Temporal_Orden Temporal Detectado Orden Temporal_Pocas Fechas Formato Fecha Más Común_DD/MM/YYYY Formato Fecha Más Común_MM-YYYY Formato Fecha Más Común_MM/YYYY Formato Fecha Más Común_Mes YYYY (ES Comp) Formato Fecha Más Común_Mon YYYY (EN) Formato Fecha Más Común_Month YYYY (EN) Formato Fecha Más Común_Rango YYYY-YYYY Formato Fecha Más Común_SpaCy DATE (Sin clasificar) Formato Fecha Más Común_YYYY Formato Fecha Más Común_YYYY (SpaCy) Fuente principal_ArialMT Fuente principal_Calibri Fuente principal_Lato-Regular Fuente principal_OpenSans-Regular Fuente principal_Otra Fuente principal_Roboto-Regular Fuente principal_Tahoma Legibilidad general_Buena Legibilidad general_Potencialmente Deficiente Consistencia tamaños fuente_Consistente Consistencia tamaños fuente_Inconsistente Consistencia márgenes (aprox)_Consistente Consistencia márgenes (aprox)_Inconsistente Uso de colores (texto)_No Uso de colores (texto)_Sí Uso de colores (dibujos)_No Uso de colores (dibujos)_Sí Deteccion Foto Perfil_No se detectaron imágenes candidatas Deteccion Foto Perfil_Posible Foto Detectada secciones_completas
0 1 2 493 5.71 3 12 7 5 34.4 91.7 3.72 96.28 1 0 1 0 0 6 2 26 0 0 0 0 9 0 0 0 1 1 1 1 0 1 0 1 1 1 0 3692 12 16.000000 0 0 1 1 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 1 0 0 1 0 1 0 1 0 0 1 0 1 1 0 7
1 1 1 388 8.09 1 9 1 1 0.0 100.0 9.61 90.39 0 0 1 9 1 8 12 3 0 0 3 1 0 7 0 0 1 1 1 1 0 1 1 1 1 1 0 2703 9 9.000000 0 0 1 0 1 0 0 1 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 1 1 0 1 0 1 0 0 1 0 1 8
2 1 1 378 8.27 0 10 3 4 21.8 100.0 8.58 91.42 0 0 0 0 1 3 38 1 0 0 0 0 0 0 0 0 1 1 1 1 0 1 1 1 1 1 1 2761 10 13.000000 1 0 0 0 1 0 0 0 0 1 0 0 0 0 0 1 0 0 0 0 0 0 1 0 1 0 1 0 0 1 1 0 1 0 9
3 1 4 656 3.54 2 10 4 12 16.2 100.0 6.67 93.33 0 0 0 3 1 25 8 3 0 0 0 17 0 0 18 0 1 1 1 0 0 1 1 1 1 1 0 4732 10 14.916667 0 0 1 1 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 1 0 0 1 0 0 1 0 1 1 0 0 1 0 1 7
4 1 3 160 4.71 0 10 6 7 31.2 5.2 11.29 88.71 1 1 0 5 1 0 7 0 0 2 5 8 2 3 1 0 1 1 1 1 1 1 1 1 1 1 1 4562 10 13.714286 0 0 1 0 1 0 0 0 0 0 0 0 0 1 0 0 0 1 0 0 0 0 1 0 0 1 1 0 0 1 1 0 0 1 10
... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ...
630 0 6 1372 4.37 0 11 8 6 32.7 36.8 6.72 93.28 0 0 1 8 1 6 5 0 6 1 0 3 3 6 6 0 1 1 1 1 1 1 1 1 1 1 0 8464 11 13.166667 0 0 1 0 1 0 0 0 0 1 0 0 0 0 0 0 1 0 0 0 0 0 1 0 0 1 0 1 0 1 0 1 0 1 9
631 0 10 3729 7.54 3 11 7 8 8.1 5.4 2.71 97.29 0 0 0 1 1 0 0 2 4 0 12 0 34 0 5 0 1 0 1 1 1 1 1 1 1 1 0 25210 11 13.125000 0 0 1 1 0 0 0 0 0 0 0 0 0 1 0 0 1 0 0 0 0 0 1 0 0 1 1 0 1 0 0 1 1 0 8
632 0 3 899 6.13 1 11 4 6 62.7 4.5 5.04 94.96 0 0 0 0 1 5 8 12 0 17 1 1 35 0 0 4 1 1 1 1 1 1 1 1 1 1 1 6154 11 14.166667 0 0 1 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 1 0 0 1 0 0 1 1 0 1 0 1 0 1 0 10
633 0 1 185 3.93 2 10 2 4 0.0 100.0 6.25 93.75 0 0 0 0 1 0 1 5 0 0 5 5 3 0 2 0 1 1 1 1 0 1 1 1 1 1 0 1313 10 18.000000 0 0 1 1 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 1 0 0 1 0 1 0 1 0 1 0 0 1 1 0 8
634 0 4 534 5.95 0 11 3 2 39.9 0.5 5.55 94.45 1 0 0 2 1 1 0 2 4 1 0 1 1 4 0 0 1 1 1 1 1 1 1 1 1 1 1 7693 11 10.500000 0 0 1 0 1 0 0 0 1 0 0 0 0 0 0 0 0 0 0 1 0 0 1 0 1 0 0 1 0 1 0 1 0 1 10

614 rows × 77 columns

In [28]:
# Comparar distribuciones por clase de la variable objetivo solo para columnas con "tiene_seccion"
target = 'Passed'  # Cambia esto si tu variable objetivo tiene otro nombre

# Filtrar columnas que contienen "tiene_seccion" en su nombre
secciones_completas_cols = [col for col in df.columns if 'secciones_completas' in col]

# Iterar sobre las columnas que cumplen con la condición
for col in secciones_completas_cols:
    plt.figure(figsize=(10, 5))

    # Separar por clases de la variable objetivo
    if target in df.columns:
        sns.kdeplot(data=df, x=col, hue=target, common_norm=False, fill=True, alpha=0.4)

    # Títulos para los gráficos
    plt.title(f"Distribuciones por clase de '{target}' para '{col}'")
    plt.xlabel(col)
    plt.ylabel("Densidad")

    plt.tight_layout()
    plt.show()
No description has been provided for this image
In [29]:
df.to_csv('../Bases/base_cvs/baseCVsIngVar.csv')

Exploración de la variable Passed con la nueva base¶

In [30]:
if 'Passed' in df.columns:
    print("\nDistribución de la variable objetivo 'Passed':")
    passed_counts = df['Passed'].value_counts()
    print(passed_counts)

    # Visualización de la distribución
    plt.figure(figsize=(6, 4))
    sns.countplot(x='Passed', data=df)
    plt.title('Distribución de la Variable Objetivo "Passed"')
    plt.xlabel('Passed (0 = No Pasó, 1 = Pasó)')
    plt.ylabel('Cantidad de CVs')
    plt.show()

        # Revisar si hay desbalanceo significativo
    imbalance_ratio = passed_counts.min() / passed_counts.max()
    print(f"Ratio de desbalanceo (minoritaria/mayoritaria): {imbalance_ratio:.2f}")
    if imbalance_ratio < 0.1: # Umbral ejemplo
      print("Advertencia: El dataset parece estar muy desbalanceado.")

else:
    print("Error: La columna 'Passed' no se encontró en el DataFrame.")
    # Detener ejecución si 'Passed' no existe o manejar el error
    # exit()
Distribución de la variable objetivo 'Passed':
Passed
0    352
1    262
Name: count, dtype: int64
No description has been provided for this image
Ratio de desbalanceo (minoritaria/mayoritaria): 0.74

Variable númerica vs passed¶

In [31]:
# Identificar columnas numéricas y binarias/categóricas (aproximación)
# Excluimos 'Passed' de las features
features = df.drop('Passed', axis=1).columns
numerical_cols = df[features].select_dtypes(include=np.number).columns
binary_cols = [col for col in numerical_cols if df[col].nunique() == 2 and df[col].min() == 0 and df[col].max() == 1]
# Consideraremos el resto de columnas numéricas como continuas o discretas (no estrictamente binarias 0/1)
continuous_numerical_cols = [col for col in numerical_cols if col not in binary_cols]

print(f"\nColumnas numéricas continuas/discretas identificadas ({len(continuous_numerical_cols)}): {continuous_numerical_cols[:10]}...") # Mostrar solo algunas
print(f"Columnas binarias (0/1) identificadas ({len(binary_cols)}): {binary_cols[:10]}...") # Mostrar solo algunas

# 3.1: Variables Numéricas vs 'Passed'
print("\n--- Análisis: Variables Numéricas Continuas vs Passed ---")
# Comparar medias
print("\nMedias de variables numéricas por grupo 'Passed':")
print(df.groupby('Passed')[continuous_numerical_cols].mean().T.head(20)) # Mostrar solo las 10 primeras

# Realizar T-tests (ejemplo para algunas variables)
print("\nResultados T-test (p-value < 0.05 sugiere diferencia significativa):")
for col in numerical_cols: # Ejemplo
    if col in continuous_numerical_cols:
        group0 = df[df['Passed'] == 0][col].dropna()
        group1 = df[df['Passed'] == 1][col].dropna()
        if len(group0) > 1 and len(group1) > 1:
             stat, p_value = ttest_ind(group0, group1)
             print(f"  - {col}: p-value = {p_value:.4f}")

plt.figure(figsize=(15, 5 * (len(continuous_numerical_cols)//3 + 1)))
for i, col in enumerate(continuous_numerical_cols[:6]): # Visualizar las primeras 6
    plt.subplot((len(continuous_numerical_cols)//3 + 1), 3, i + 1)
    sns.boxplot(x='Passed', y=col, data=df)
    plt.title(f'{col} vs Passed')
plt.tight_layout()
plt.show()
Columnas numéricas continuas/discretas identificadas (27): ['Numero de Paginas', 'Cantidad de Palabras', 'Densidad Informacion (%)', 'Fechas Detectadas (Count)', 'Tamaño cuerpo probable', 'Variedad de fuentes', 'Variedad de tamaños', 'Uso de negritas (estimado %)', 'Uso de cursivas (estimado %)', 'Porcentaje Lenguaje Técnico']...
Columnas binarias (0/1) identificadas (49): ['LinkedIn', 'GitHub', 'Website/Otro', 'Tiene Elementos Graficos', 'Seccion_education', 'Seccion_work_experience', 'Seccion_skills', 'Seccion_certifications', 'Seccion_achievements', 'Seccion_professional_profile']...

--- Análisis: Variables Numéricas Continuas vs Passed ---

Medias de variables numéricas por grupo 'Passed':
Passed                                 0           1
Numero de Paginas               2.676136    3.022901
Cantidad de Palabras          563.153409  594.183206
Densidad Informacion (%)        5.952472    5.891947
Fechas Detectadas (Count)       1.323864    1.446565
Tamaño cuerpo probable         10.394886   10.057252
Variedad de fuentes             4.630682    4.797710
Variedad de tamaños             5.181818    5.248092
Uso de negritas (estimado %)   21.055682   19.104198
Uso de cursivas (estimado %)   55.751989   56.175191
Porcentaje Lenguaje Técnico     7.454574    7.379008
Porcentaje Lenguaje Genérico   92.545426   92.620992
Cantidad de imágenes            3.281250    4.061069
Lineas_education                6.053977    6.507634
Lineas_work_experience         11.321023   12.492366
Lineas_skills                   5.011364    6.152672
Lineas_certifications           2.403409    2.709924
Lineas_achievements             1.562500    1.732824
Lineas_professional_profile     6.073864    6.549618
Lineas_languages                4.480114    4.400763
Lineas_projects                 4.579545    5.122137

Resultados T-test (p-value < 0.05 sugiere diferencia significativa):
  - Numero de Paginas: p-value = 0.0742
  - Cantidad de Palabras: p-value = 0.3994
  - Densidad Informacion (%): p-value = 0.7539
  - Fechas Detectadas (Count): p-value = 0.4342
  - Tamaño cuerpo probable: p-value = 0.2822
  - Variedad de fuentes: p-value = 0.3417
  - Variedad de tamaños: p-value = 0.7217
  - Uso de negritas (estimado %): p-value = 0.0653
  - Uso de cursivas (estimado %): p-value = 0.9074
  - Porcentaje Lenguaje Técnico: p-value = 0.8096
  - Porcentaje Lenguaje Genérico: p-value = 0.8096
  - Cantidad de imágenes: p-value = 0.3716
  - Lineas_education: p-value = 0.5081
  - Lineas_work_experience: p-value = 0.5255
  - Lineas_skills: p-value = 0.1523
  - Lineas_certifications: p-value = 0.5692
  - Lineas_achievements: p-value = 0.7194
  - Lineas_professional_profile: p-value = 0.6211
  - Lineas_languages: p-value = 0.8839
  - Lineas_projects: p-value = 0.4619
  - Lineas_publications: p-value = 0.1469
  - Lineas_training_courses: p-value = 0.4100
  - Lineas_volunteer_work: p-value = 0.5063
  - texto_extraido_len: p-value = 0.0545
  - Tamaño de fuente más usado: p-value = 0.2822
  - Promedio tamaño fuente: p-value = 0.7138
  - secciones_completas: p-value = 0.0097
No description has been provided for this image

Análisis incial¶

Lo primero que debemos tener en cuenta, es que en términos de media, existen más CVs dentro de las que pasaron con un mayor número en las variables Numero de Paginas, Cantidad de Palabras, Cantidad de imágenes, Lineas_work_experience, Lineas_skills, Lineas_professional_profile, texto_extraido_len, secciones_completas. Esto, nos da a entender que es muy posible que las HVs más largas, hayan tenido una mayor probabilidad de éxito.

Aunque, para descartar el simple hecho de que es porque tienen más experiencia, es necesario crear una proporción de experiencia laboral vs total del texto. Esto se hará a continuación.

De la misma manera, podemos ver que las variables Tamaño cuerpo (fuente) probable, Uso de negritas (estimado %) cuentan con menor tamaño en las CVs que pasaron, lo que nos da una idea de que se buscan CVs con tamaños de fuente algo más "conservadores" y menos negritas en las CVs.

Las variables Densidad Informacion (%) y Porcentaje Lenguaje Técnico, contrario a lo que se pensaría, son casi idénticas en ambos grupos, por lo que no deberían representar algo significativo en la cv. aunque lo podemos ver más adelante.

Prueba-t¶

La prueba t compara medias y nos muestra si hay una significancia estadística o no entre las diferencias observadas.

De acuerdo con esta prueba texto_extraido_len y secciones_completas son las variables que más significancia estadística cuentan entre los grupos passed y no-passed. De acuerdo con esto, es posible decir que las CVs con mayor longitud en su texto así como con mayor cantidad de secciones completas, son las que más probabilidad tienen de pasar.

Así mismo, hay otras que tienen una significancia algo más leve, como lo son Número de Páginas y Uso de negritas (estimado %), en donde con un mayor número de páginas existe una leve probabilidad de pasar, mientras que con un menor número de negritas, también hay una leve probabilidad de encontrarse en el grupo que pasó.

Variables Binarias vs Passed¶

In [32]:
# 3.2: Variables Binarias vs 'Passed'
print("\n--- Análisis: Variables Binarias vs Passed ---")
# Tablas de contingencia y Chi-cuadrado (ejemplo para algunas variables)
print("\nResultados Chi-Cuadrado (p-value < 0.05 sugiere asociación significativa):")
significant_binary_vars = []
for col in binary_cols[:51]: # Analizar las primeras 10 binarias como ejemplo
    contingency_table = pd.crosstab(df[col], df['Passed'])
    #print(f"\nTabla de Contingencia para {col}:\n{contingency_table}")
    try:
        chi2, p, dof, expected = chi2_contingency(contingency_table)
        print(f"  - {col}: p-value = {p:.4f}")
        if p < 0.1:
            significant_binary_vars.append(col)
    except ValueError:
         print(f"  - {col}: No se pudo calcular Chi2 (posiblemente poca variación).")

print(f"\nVariables binarias con asociación significativa (p<0.05, ejemplo): {significant_binary_vars}")

# Visualización (ejemplo con Count Plots para variables significativas)
if significant_binary_vars:
    plt.figure(figsize=(15, 5 * (len(significant_binary_vars)//3 + 1)))
    for i, col in enumerate(significant_binary_vars):
        plt.subplot((len(significant_binary_vars)//3 + 1), 3, i + 1)
        sns.countplot(x=col, hue='Passed', data=df, palette='viridis')
        plt.title(f'{col} vs Passed')
    plt.tight_layout()
    plt.show()
else:
    print("No se encontraron variables binarias significativamente asociadas en el ejemplo analizado.")
--- Análisis: Variables Binarias vs Passed ---

Resultados Chi-Cuadrado (p-value < 0.05 sugiere asociación significativa):
  - LinkedIn: p-value = 1.0000
  - GitHub: p-value = 0.8714
  - Website/Otro: p-value = 0.0124
  - Tiene Elementos Graficos: p-value = 0.7574
  - Seccion_education: p-value = 0.8172
  - Seccion_work_experience: p-value = 1.0000
  - Seccion_skills: p-value = 0.1659
  - Seccion_certifications: p-value = 0.4531
  - Seccion_achievements: p-value = 0.5532
  - Seccion_professional_profile: p-value = 0.7648
  - Seccion_languages: p-value = 0.1161
  - Seccion_projects: p-value = 0.1795
  - Seccion_publications: p-value = 0.2209
  - Seccion_training_courses: p-value = 0.0325
  - Seccion_volunteer_work: p-value = 0.3840
  - Formato Texto (Lineas)_Mixto: p-value = 0.6230
  - Formato Texto (Lineas)_Párrafos: p-value = 0.5117
  - Formato Texto (Lineas)_Viñetas: p-value = 0.4070
  - Orden Temporal_Orden Temporal Detectado: p-value = 0.9592
  - Orden Temporal_Pocas Fechas: p-value = 0.9592
  - Formato Fecha Más Común_DD/MM/YYYY: p-value = 1.0000
  - Formato Fecha Más Común_MM-YYYY: p-value = 0.2148
  - Formato Fecha Más Común_MM/YYYY: p-value = 0.0824
  - Formato Fecha Más Común_Mes YYYY (ES Comp): p-value = 1.0000
  - Formato Fecha Más Común_Mon YYYY (EN): p-value = 0.4511
  - Formato Fecha Más Común_Month YYYY (EN): p-value = 0.8390
  - Formato Fecha Más Común_Rango YYYY-YYYY: p-value = 0.2665
  - Formato Fecha Más Común_SpaCy DATE (Sin clasificar): p-value = 0.1460
  - Formato Fecha Más Común_YYYY: p-value = 0.8914
  - Formato Fecha Más Común_YYYY (SpaCy): p-value = 1.0000
  - Fuente principal_ArialMT: p-value = 0.7960
  - Fuente principal_Calibri: p-value = 0.9501
  - Fuente principal_Lato-Regular: p-value = 0.4896
  - Fuente principal_OpenSans-Regular: p-value = 0.9581
  - Fuente principal_Otra: p-value = 0.7117
  - Fuente principal_Roboto-Regular: p-value = 0.5722
  - Fuente principal_Tahoma: p-value = 0.1361
  - Legibilidad general_Buena: p-value = 0.2258
  - Legibilidad general_Potencialmente Deficiente: p-value = 0.2258
  - Consistencia tamaños fuente_Consistente: p-value = 0.7990
  - Consistencia tamaños fuente_Inconsistente: p-value = 0.7990
  - Consistencia márgenes (aprox)_Consistente: p-value = 0.6508
  - Consistencia márgenes (aprox)_Inconsistente: p-value = 0.6508
  - Uso de colores (texto)_No: p-value = 0.0973
  - Uso de colores (texto)_Sí: p-value = 0.0973
  - Uso de colores (dibujos)_No: p-value = 0.8346
  - Uso de colores (dibujos)_Sí: p-value = 0.8346
  - Deteccion Foto Perfil_No se detectaron imágenes candidatas: p-value = 0.2064
  - Deteccion Foto Perfil_Posible Foto Detectada: p-value = 0.2064

Variables binarias con asociación significativa (p<0.05, ejemplo): ['Website/Otro', 'Seccion_training_courses', 'Formato Fecha Más Común_MM/YYYY', 'Uso de colores (texto)_No', 'Uso de colores (texto)_Sí']
No description has been provided for this image

Prueba chi-cuadrado¶

La prueba Chi-cuadrado muestra si existe una asociación entre variables categóricas.

Siendo así, las variables Website/Otro, Seccion_training_courses, son las que presentan una mayor significancia estadística frente a su asociación con la variable 'Passed', lo cual nos refiere que personas que tienen un website personal, portafolio o incluso un link a los productos que construyeron, tienen una mayor probabilidad de pertenecer al grupo de Passed. Por otro lado, es posible que las personas que muestran educación adicional a al tradicional, teniendo cursos, certificaciones, diplomados, etc, tiene mayor probabilidad de pasar.

Así mismo, variables que muestran relación aunque algo más leve son Seccion_languages, Seccion_publications, Formato Fecha Más Común_MM/YYYY, Fuente principal_Tahoma, Uso de colores (texto)_No/Si, lo que nos dice que personas que muestran explícitamente que hablan otro idioma o que realizaron la publicación de algún trabajo académico, aplicación o programa (recordemos que todos son Desarrolladores de software) tienen ligeramente más posibilidad de pertenecer al grupo que pasó. Así mismo, las personas que mostraron las fechas en las que trabajaron usando el formato MM/YYYY, ligeramente pueden estar pasando más frente a personas que no. Esto teniendo en cuenta la variedad de fechas, muestra que es importante mostrar no solo el año como en una gran cantidad de CVs, sino también el mes, en el formato de número el cual puede ser más fácil de entender para muchas personas y más sencillo entender la duración de las personas en sus respectivas experiencias. Por otro lado, la fuente principal tahoma, aunque diciente, posiblemente también es porque es una fuente sin serifas y de fácil lectura. Por otro lado, el uso de colores levemente nos puede ubicar en la variable passed.

Nuevas variables¶

Crearemos el ratio de work-experience/longitud total, para entender si la cantidad de experiencia laboral total influye en algo. Así mismo, una que nos compare el número de secciones frente al texto total, con el objetivo de entender que tan densa es cada sección y si esta completitud afecta en la cantidad del texto también.

In [33]:
denominator_len = df['texto_extraido_len']
df['Ratio_Lineas_Experiencia_len'] = np.divide(
    df['Lineas_work_experience'],
    denominator_len,
    out=np.zeros_like(df['Lineas_work_experience'], dtype=float), # Salida por defecto (0.0)
    where=denominator_len!=0 # Condición para realizar la división
)
print("- Variable 'Ratio_Lineas_Experiencia_len' creada.")

# Opción B: Basado en cantidad de palabras
# Manejo de división por cero: si Cantidad de Palabras es 0, el ratio será 0.
denominator_words = df['Cantidad de Palabras']
df['Ratio_Lineas_Experiencia_words'] = np.divide(
    df['Lineas_work_experience'],
    denominator_words,
    out=np.zeros_like(df['Lineas_work_experience'], dtype=float), # Salida por defecto (0.0)
    where=denominator_words!=0 # Condición para realizar la división
)
print("- Variable 'Ratio_Lineas_Experiencia_words' creada.")


# --- Variable 2: Densidad_Texto_Por_Seccion ---
# Calcula la longitud promedio del texto por sección detectada.
# Manejo de división por cero: si secciones_completas es 0, asignamos 0 (o podrías usar np.nan).
denominator_secciones = df['secciones_completas']
df['Densidad_Texto_Por_Seccion'] = np.divide(
    df['texto_extraido_len'],
    denominator_secciones,
    out=np.zeros_like(df['texto_extraido_len'], dtype=float), # Salida por defecto (0.0)
    where=denominator_secciones!=0 # Condición para realizar la división
)
# Podrías considerar usar Cantidad de Palabras en lugar de texto_extraido_len aquí también si prefieres
# df['Densidad_Palabras_Por_Seccion'] = np.divide(...)
print("- Variable 'Densidad_Texto_Por_Seccion' creada.")


# --- Verificar las nuevas columnas ---
print("\n--- Primeras filas con las nuevas variables ---")
# Selecciona cuál de los ratios de experiencia quieres ver o muestra ambos
columns_to_show = [
    'Lineas_work_experience', 'texto_extraido_len', 'Cantidad de Palabras', 'secciones_completas',
    'Ratio_Lineas_Experiencia_len', # O '_words'
    'Densidad_Texto_Por_Seccion'
]
# Filtrar por si alguna columna base no existiera (aunque deberían existir)
columns_to_show = [col for col in columns_to_show if col in df.columns]
print(df[columns_to_show].head())

print("\n--- Descriptivos básicos de las nuevas variables ---")
new_columns = [col for col in ['Ratio_Lineas_Experiencia_len', 'Ratio_Lineas_Experiencia_words', 'Densidad_Texto_Por_Seccion'] if col in df.columns]
if new_columns:
    print(df[new_columns].describe())
else:
    print("No se encontraron las nuevas columnas para describir.")
- Variable 'Ratio_Lineas_Experiencia_len' creada.
- Variable 'Ratio_Lineas_Experiencia_words' creada.
- Variable 'Densidad_Texto_Por_Seccion' creada.

--- Primeras filas con las nuevas variables ---
   Lineas_work_experience  texto_extraido_len  Cantidad de Palabras  \
0                       2                3692                   493   
1                      12                2703                   388   
2                      38                2761                   378   
3                       8                4732                   656   
4                       7                4562                   160   

   secciones_completas  Ratio_Lineas_Experiencia_len  \
0                    7                      0.000542   
1                    8                      0.004440   
2                    9                      0.013763   
3                    7                      0.001691   
4                   10                      0.001534   

   Densidad_Texto_Por_Seccion  
0                  527.428571  
1                  337.875000  
2                  306.777778  
3                  676.000000  
4                  456.200000  

--- Descriptivos básicos de las nuevas variables ---
       Ratio_Lineas_Experiencia_len  Ratio_Lineas_Experiencia_words  \
count                    614.000000                      614.000000   
mean                       0.002650                        0.024221   
std                        0.004357                        0.034380   
min                        0.000000                        0.000000   
25%                        0.000263                        0.002242   
50%                        0.000922                        0.011080   
75%                        0.003100                        0.032155   
max                        0.043824                        0.256454   

       Densidad_Texto_Por_Seccion  
count                  614.000000  
mean                   594.936810  
std                    342.567670  
min                    126.571429  
25%                    370.446429  
50%                    517.072222  
75%                    716.625000  
max                   3151.250000  
In [34]:
df
Out[34]:
Passed Numero de Paginas Cantidad de Palabras Densidad Informacion (%) Fechas Detectadas (Count) Tamaño cuerpo probable Variedad de fuentes Variedad de tamaños Uso de negritas (estimado %) Uso de cursivas (estimado %) Porcentaje Lenguaje Técnico Porcentaje Lenguaje Genérico LinkedIn GitHub Website/Otro Cantidad de imágenes Tiene Elementos Graficos Lineas_education Lineas_work_experience Lineas_skills Lineas_certifications Lineas_achievements Lineas_professional_profile Lineas_languages Lineas_projects Lineas_publications Lineas_training_courses Lineas_volunteer_work Seccion_education Seccion_work_experience Seccion_skills Seccion_certifications Seccion_achievements Seccion_professional_profile Seccion_languages Seccion_projects Seccion_publications Seccion_training_courses Seccion_volunteer_work texto_extraido_len Tamaño de fuente más usado Promedio tamaño fuente Formato Texto (Lineas)_Mixto Formato Texto (Lineas)_Párrafos Formato Texto (Lineas)_Viñetas Orden Temporal_Orden Temporal Detectado Orden Temporal_Pocas Fechas Formato Fecha Más Común_DD/MM/YYYY Formato Fecha Más Común_MM-YYYY Formato Fecha Más Común_MM/YYYY Formato Fecha Más Común_Mes YYYY (ES Comp) Formato Fecha Más Común_Mon YYYY (EN) Formato Fecha Más Común_Month YYYY (EN) Formato Fecha Más Común_Rango YYYY-YYYY Formato Fecha Más Común_SpaCy DATE (Sin clasificar) Formato Fecha Más Común_YYYY Formato Fecha Más Común_YYYY (SpaCy) Fuente principal_ArialMT Fuente principal_Calibri Fuente principal_Lato-Regular Fuente principal_OpenSans-Regular Fuente principal_Otra Fuente principal_Roboto-Regular Fuente principal_Tahoma Legibilidad general_Buena Legibilidad general_Potencialmente Deficiente Consistencia tamaños fuente_Consistente Consistencia tamaños fuente_Inconsistente Consistencia márgenes (aprox)_Consistente Consistencia márgenes (aprox)_Inconsistente Uso de colores (texto)_No Uso de colores (texto)_Sí Uso de colores (dibujos)_No Uso de colores (dibujos)_Sí Deteccion Foto Perfil_No se detectaron imágenes candidatas Deteccion Foto Perfil_Posible Foto Detectada secciones_completas Ratio_Lineas_Experiencia_len Ratio_Lineas_Experiencia_words Densidad_Texto_Por_Seccion
0 1 2 493 5.71 3 12 7 5 34.4 91.7 3.72 96.28 1 0 1 0 0 6 2 26 0 0 0 0 9 0 0 0 1 1 1 1 0 1 0 1 1 1 0 3692 12 16.000000 0 0 1 1 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 1 0 0 1 0 1 0 1 0 0 1 0 1 1 0 7 0.000542 0.004057 527.428571
1 1 1 388 8.09 1 9 1 1 0.0 100.0 9.61 90.39 0 0 1 9 1 8 12 3 0 0 3 1 0 7 0 0 1 1 1 1 0 1 1 1 1 1 0 2703 9 9.000000 0 0 1 0 1 0 0 1 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 1 1 0 1 0 1 0 0 1 0 1 8 0.004440 0.030928 337.875000
2 1 1 378 8.27 0 10 3 4 21.8 100.0 8.58 91.42 0 0 0 0 1 3 38 1 0 0 0 0 0 0 0 0 1 1 1 1 0 1 1 1 1 1 1 2761 10 13.000000 1 0 0 0 1 0 0 0 0 1 0 0 0 0 0 1 0 0 0 0 0 0 1 0 1 0 1 0 0 1 1 0 1 0 9 0.013763 0.100529 306.777778
3 1 4 656 3.54 2 10 4 12 16.2 100.0 6.67 93.33 0 0 0 3 1 25 8 3 0 0 0 17 0 0 18 0 1 1 1 0 0 1 1 1 1 1 0 4732 10 14.916667 0 0 1 1 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 1 0 0 1 0 0 1 0 1 1 0 0 1 0 1 7 0.001691 0.012195 676.000000
4 1 3 160 4.71 0 10 6 7 31.2 5.2 11.29 88.71 1 1 0 5 1 0 7 0 0 2 5 8 2 3 1 0 1 1 1 1 1 1 1 1 1 1 1 4562 10 13.714286 0 0 1 0 1 0 0 0 0 0 0 0 0 1 0 0 0 1 0 0 0 0 1 0 0 1 1 0 0 1 1 0 0 1 10 0.001534 0.043750 456.200000
... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ...
630 0 6 1372 4.37 0 11 8 6 32.7 36.8 6.72 93.28 0 0 1 8 1 6 5 0 6 1 0 3 3 6 6 0 1 1 1 1 1 1 1 1 1 1 0 8464 11 13.166667 0 0 1 0 1 0 0 0 0 1 0 0 0 0 0 0 1 0 0 0 0 0 1 0 0 1 0 1 0 1 0 1 0 1 9 0.000591 0.003644 940.444444
631 0 10 3729 7.54 3 11 7 8 8.1 5.4 2.71 97.29 0 0 0 1 1 0 0 2 4 0 12 0 34 0 5 0 1 0 1 1 1 1 1 1 1 1 0 25210 11 13.125000 0 0 1 1 0 0 0 0 0 0 0 0 0 1 0 0 1 0 0 0 0 0 1 0 0 1 1 0 1 0 0 1 1 0 8 0.000000 0.000000 3151.250000
632 0 3 899 6.13 1 11 4 6 62.7 4.5 5.04 94.96 0 0 0 0 1 5 8 12 0 17 1 1 35 0 0 4 1 1 1 1 1 1 1 1 1 1 1 6154 11 14.166667 0 0 1 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 1 0 0 1 0 0 1 1 0 1 0 1 0 1 0 10 0.001300 0.008899 615.400000
633 0 1 185 3.93 2 10 2 4 0.0 100.0 6.25 93.75 0 0 0 0 1 0 1 5 0 0 5 5 3 0 2 0 1 1 1 1 0 1 1 1 1 1 0 1313 10 18.000000 0 0 1 1 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 1 0 0 1 0 1 0 1 0 1 0 0 1 1 0 8 0.000762 0.005405 164.125000
634 0 4 534 5.95 0 11 3 2 39.9 0.5 5.55 94.45 1 0 0 2 1 1 0 2 4 1 0 1 1 4 0 0 1 1 1 1 1 1 1 1 1 1 1 7693 11 10.500000 0 0 1 0 1 0 0 0 1 0 0 0 0 0 0 0 0 0 0 1 0 0 1 0 1 0 0 1 0 1 0 1 0 1 10 0.000000 0.000000 769.300000

614 rows × 80 columns

Prueba-t con las nuevas variables¶

In [35]:
# Lista de las nuevas variables a probar (ajusta según las que hayas creado/elegido)
nuevas_variables_numericas = [
    'Ratio_Lineas_Experiencia_len',   # O usa '_words' si prefieres esa versión
    'Ratio_Lineas_Experiencia_words', # Descomenta si quieres probar ambas
    'Densidad_Texto_Por_Seccion'
]

# Verificar que las columnas existan
variables_existentes = [var for var in nuevas_variables_numericas if var in df.columns]

if not variables_existentes:
    print("Error: No se encontraron las nuevas columnas especificadas en el DataFrame.")
else:
    print("\n--- Análisis T-test: Nuevas Variables Numéricas vs Passed ---")

    # Separar los datos en dos grupos basados en 'Passed'
    grupo_no_paso = df[df['Passed'] == 0]
    grupo_paso = df[df['Passed'] == 1]

    # Calcular y mostrar las medias para comparación visual
    print("\nMedias de las nuevas variables por grupo 'Passed':")
    try:
        medias_nuevas = df.groupby('Passed')[variables_existentes].mean().transpose()
        print(medias_nuevas)
    except Exception as e:
        print(f"No se pudieron calcular las medias grupales: {e}")


    print("\nResultados T-test para nuevas variables (p-value < 0.05 sugiere diferencia significativa):")

    for var in variables_existentes:
        # Obtener los datos de cada grupo para la variable actual, quitando NaNs si los hubiera
        datos_no_paso = grupo_no_paso[var].dropna()
        datos_paso = grupo_paso[var].dropna()

        # Realizar el T-test solo si hay suficientes datos en ambos grupos
        if len(datos_no_paso) >= 2 and len(datos_paso) >= 2:
            # Usamos equal_var=False (Test de Welch) que es más robusto si las varianzas son diferentes
            # nan_policy='omit' maneja si aún quedaran NaNs (aunque el dropna ya lo hizo)
            t_stat, p_value = ttest_ind(datos_no_paso, datos_paso,
                                        equal_var=False, nan_policy='omit')
            print(f"  - {var}: p-value = {p_value:.4f}")
        else:
            print(f"  - {var}: No se pudo realizar el T-test (datos insuficientes en algún grupo después de quitar NaNs).")
--- Análisis T-test: Nuevas Variables Numéricas vs Passed ---

Medias de las nuevas variables por grupo 'Passed':
Passed                                   0           1
Ratio_Lineas_Experiencia_len      0.002642    0.002660
Ratio_Lineas_Experiencia_words    0.023435    0.025279
Densidad_Texto_Por_Seccion      575.801655  620.645109

Resultados T-test para nuevas variables (p-value < 0.05 sugiere diferencia significativa):
  - Ratio_Lineas_Experiencia_len: p-value = 0.9583
  - Ratio_Lineas_Experiencia_words: p-value = 0.5155
  - Densidad_Texto_Por_Seccion: p-value = 0.1105

La prueba t con estas nuevas variables nos da a entender que la longitud de las CVs vs la longitud de la experiencia laboral no es significativa frente a si pasa o no, por el contrario, la longitud promedio de cada sección si es levemente significativa, lo cual nos dice que la cantidad de experiencia misma de los candidatos en si mismo no es lo que hacía que la longitud fuera un factor importante en que las CVs estuvieran en un grupo de si pasó o no pasó. Pero, si es importante que cada sección en la CV si tenga contenido algo más largo.

Identificación de variables con Feature Importance¶

Utilizaremos el RF también para evaluar como funciona la relación entre variables y la importancia que tendrían en un eventual modelo de RF

In [36]:
# --- 1. Preparar Datos ---
print("Preparando datos para Random Forest...")

# Define la columna objetivo
target_column = 'Passed'

# Asegúrate de que no haya columnas de identificación o texto aquí
try:
    X = df.drop(columns=[target_column])
    y = df[target_column]

    # --- Manejo de Posibles NaNs (importante para scikit-learn) ---
    # Aunque codificaste, revisemos y imputemos si es necesario (ej. con la media)
    # Nota: Imputar con la media puede no ser ideal para binarias/one-hot,
    # podrías usar strategy='most_frequent' o 'constant' con fill_value=0.
    # Pero para feature importance con RF suele ser aceptable.
    if X.isnull().sum().sum() > 0:
        print(f"Se encontraron {X.isnull().sum().sum()} valores NaN. Imputando con la media...")
        # Guardar nombres de columnas antes de imputar
        feature_names = X.columns
        imputer = SimpleImputer(strategy='mean')
        X = pd.DataFrame(imputer.fit_transform(X), columns=feature_names)
        print("Imputación completada.")
    else:
        feature_names = X.columns
        print("No se encontraron valores NaN en las features.")

    # Convertir a numpy array si es necesario (usualmente no hace falta para RF)
    # X_array = X.values
    # y_array = y.values

    # --- 2. Entrenar Random Forest ---
    print("\nEntrenando Random Forest...")
    # Puedes ajustar n_estimators (número de árboles)
    # class_weight='balanced' ayuda si las clases 0 y 1 están desbalanceadas
    rf_model = RandomForestClassifier(n_estimators=150, # Más árboles para estabilidad
                                      random_state=42,
                                      n_jobs=-1,         # Usar todos los cores disponibles
                                      class_weight='balanced',
                                      oob_score=True)    # Usar Out-of-Bag score para una estimación rápida

    # Entrenar con todos los datos (común para feature importance exploratorio)
    # O podrías dividir en train/test y usar X_train, y_train si prefieres
    rf_model.fit(X, y)

    print(f"Modelo entrenado. OOB Score: {rf_model.oob_score_:.4f}") # Estimación del accuracy

    # --- 3. Extraer y Mostrar Importancia ---
    print("\nCalculando y mostrando importancia de variables...")
    importances = rf_model.feature_importances_

    # Crear un DataFrame para visualizar mejor
    importance_df = pd.DataFrame({'Feature': feature_names, 'Importance': importances})

    # Ordenar por importancia descendente
    importance_df = importance_df.sort_values(by='Importance', ascending=False).reset_index(drop=True)

    print("\n--- Importancia de Variables según Random Forest (Top 30) ---")
    print(importance_df.head(30))

    # Guardar la tabla completa en un CSV (opcional)
    # output_importance_file = "importancia_variables_rf.csv"
    # importance_df.to_csv(output_importance_file, index=False)
    # print(f"\nImportancia completa guardada en: {output_importance_file}")

    # --- 4. Graficar Importancias (Opcional) ---
    print("\nGenerando gráfico de importancia (Top 25)...")
    try:
        plt.figure(figsize=(12, 10)) # Ajustar tamaño si es necesario
        n_top_features_plot = 25
        sns.barplot(x='Importance', y='Feature', data=importance_df.head(n_top_features_plot), palette='viridis')
        plt.title(f'Top {n_top_features_plot} Feature Importances (Random Forest)')
        plt.xlabel('Importance Score')
        plt.ylabel('Feature')
        plt.tight_layout()
        plt.show()
    except ImportError:
        print("\nPara graficar, necesitas instalar matplotlib y seaborn:")
        print("pip install matplotlib seaborn")
    except Exception as e_plot:
        print(f"\nNo se pudo generar el gráfico: {e_plot}")


except KeyError as e:
    print(f"Error: Columna no encontrada en el DataFrame. Asegúrate que '{target_column}' existe. Detalle: {e}")
except Exception as e:
    print(f"Ocurrió un error inesperado durante el análisis de importancia: {e}")
Preparando datos para Random Forest...
No se encontraron valores NaN en las features.

Entrenando Random Forest...
Modelo entrenado. OOB Score: 0.5163

Calculando y mostrando importancia de variables...

--- Importancia de Variables según Random Forest (Top 30) ---
                           Feature  Importance
0     Uso de negritas (estimado %)    0.046201
1     Porcentaje Lenguaje Genérico    0.041937
2       Densidad_Texto_Por_Seccion    0.041218
3      Porcentaje Lenguaje Técnico    0.040669
4               texto_extraido_len    0.040497
5         Densidad Informacion (%)    0.039064
6           Promedio tamaño fuente    0.037944
7             Cantidad de Palabras    0.035192
8   Ratio_Lineas_Experiencia_words    0.033544
9     Ratio_Lineas_Experiencia_len    0.033018
10                   Lineas_skills    0.029353
11                Lineas_education    0.027738
12          Lineas_work_experience    0.026999
13                Lineas_languages    0.024690
14    Uso de cursivas (estimado %)    0.024299
15             Variedad de fuentes    0.023994
16             Variedad de tamaños    0.023953
17     Lineas_professional_profile    0.023928
18             Lineas_publications    0.023822
19         Lineas_training_courses    0.023541
20                 Lineas_projects    0.023045
21       Fechas Detectadas (Count)    0.019042
22             secciones_completas    0.018320
23          Tamaño cuerpo probable    0.017965
24            Cantidad de imágenes    0.017569
25      Tamaño de fuente más usado    0.016892
26           Lineas_certifications    0.016177
27               Numero de Paginas    0.016033
28           Lineas_volunteer_work    0.013341
29             Lineas_achievements    0.010605

Generando gráfico de importancia (Top 25)...
No description has been provided for this image

El modelo obtuvo un Out of Bag score del 51%, lo que diría que en un eventual modelo habría una eventual precisión del 51%, apenas mejor que escoger al azar. De acuerdo con esto, no podemos aún decidir con todas las variables, ya que no hay un patrón predictivo claro.

Análisis de multicorrelación y multicolinealidad¶

In [37]:
print("--- Calculando y Visualizando Correlaciones ---")

# 1. Seleccionar solo columnas numéricas (deberían ser todas excepto 'Passed')
#    y quitar la variable objetivo para analizar correlación entre predictores.
if 'Passed' in df.columns:
    features_df = df.drop(columns=['Passed'])
else:
    features_df = df.copy() # Si 'Passed' no estuviera por alguna razón

# Asegurarse de que solo tenemos tipos numéricos
features_df = features_df.select_dtypes(include=np.number)

# Quitar columnas con varianza cero si las hubiera (pueden dar problemas)
cols_antes = features_df.shape[1]
features_df = features_df.loc[:, features_df.var() > 1e-6] # Umbral pequeño para varianza
if cols_antes > features_df.shape[1]:
    print(f"Se quitaron {cols_antes - features_df.shape[1]} columnas con varianza cercana a cero.")

# 2. Calcular la matriz de correlación
corr_matrix = features_df.corr()

# 3. Visualizar con un Heatmap
# Puede ser grande si tienes muchas variables. Ajusta figsize.
# annot=False es mejor para muchas variables, True muestra los números.
try:
    plt.figure(figsize=(25, 22)) # Ajusta este tamaño según necesites
    sns.heatmap(corr_matrix, cmap='coolwarm', center=0, annot=False, fmt=".2f")
    plt.title('Matriz de Correlación entre Features', fontsize=16)
    plt.xticks(rotation=90)
    plt.yticks(rotation=0)
    plt.tight_layout()
    plt.show()
except Exception as e_plot:
    print(f"Error al generar heatmap: {e_plot}. Mostrando solo matriz.")
    # print(corr_matrix) # Descomentar si el heatmap falla y quieres ver la matriz

# 4. Identificar pares altamente correlacionados
print("\n--- Pares de Variables Altamente Correlacionadas (Correlación Absoluta > 0.8) ---")
threshold = 0.8 # Puedes ajustar este umbral
highly_correlated_pairs = []
# Iterar sobre la matriz triangular superior para evitar duplicados
for i in range(len(corr_matrix.columns)):
    for j in range(i):
        if abs(corr_matrix.iloc[i, j]) > threshold:
            pair_info = (corr_matrix.columns[i], corr_matrix.columns[j], round(corr_matrix.iloc[i, j], 3))
            highly_correlated_pairs.append(pair_info)
            print(f"- {pair_info[0]} y {pair_info[1]}: {pair_info[2]}")

if not highly_correlated_pairs:
    print(f"No se encontraron pares con correlación absoluta > {threshold}")

# 5. Correlación con la variable objetivo (opcional, ya tenemos idea con t-test/chi2)
# print(f"\n--- Correlación con '{target_column}' ---")
# corr_with_target = df.corr()[target_column].sort_values(ascending=False)
# print(corr_with_target.drop(target_column)) # Excluir la correlación consigo misma
--- Calculando y Visualizando Correlaciones ---
No description has been provided for this image
--- Pares de Variables Altamente Correlacionadas (Correlación Absoluta > 0.8) ---
- Porcentaje Lenguaje Genérico y Porcentaje Lenguaje Técnico: -1.0
- texto_extraido_len y Cantidad de Palabras: 0.872
- Tamaño de fuente más usado y Tamaño cuerpo probable: 1.0
- Formato Texto (Lineas)_Viñetas y Formato Texto (Lineas)_Mixto: -0.915
- Orden Temporal_Pocas Fechas y Orden Temporal_Orden Temporal Detectado: -1.0
- Legibilidad general_Potencialmente Deficiente y Legibilidad general_Buena: -1.0
- Consistencia tamaños fuente_Inconsistente y Consistencia tamaños fuente_Consistente: -1.0
- Consistencia márgenes (aprox)_Inconsistente y Consistencia márgenes (aprox)_Consistente: -1.0
- Uso de colores (texto)_Sí y Uso de colores (texto)_No: -1.0
- Uso de colores (dibujos)_Sí y Uso de colores (dibujos)_No: -1.0
- Deteccion Foto Perfil_Posible Foto Detectada y Deteccion Foto Perfil_No se detectaron imágenes candidatas: -1.0
- Ratio_Lineas_Experiencia_words y Ratio_Lineas_Experiencia_len: 0.856
- Densidad_Texto_Por_Seccion y Cantidad de Palabras: 0.835
- Densidad_Texto_Por_Seccion y texto_extraido_len: 0.95
In [38]:
# Asumiendo que 'df' está listo y 'features_df' se creó en el paso anterior
# (o vuelve a definir X como en el paso de RF importance si es necesario)
X_vif = features_df # Usar el mismo conjunto de features que para la correlación

print("\n--- Calculando Variance Inflation Factor (VIF) ---")
print("Valores > 5 indican correlación moderada-alta, > 10 indican alta correlación.")

# VIF requiere que no haya NaNs
if X_vif.isnull().sum().sum() > 0:
    print("Error: Se encontraron NaNs. Por favor, impútalos o elimínalos antes de calcular VIF.")
else:
    # Añadir una constante (columna de unos) para calcular VIF correctamente
    # Esto representa el intercepto en una regresión
    X_vif_const = add_constant(X_vif, prepend=True) # prepend=True es más común

    # Calcular VIF para cada variable original (excluyendo la constante)
    try:
        vif_data = pd.DataFrame()
        vif_data["feature"] = X_vif_const.columns[1:] # Nombres de las features originales
        vif_data["VIF"] = [variance_inflation_factor(X_vif_const.values, i)
                           for i in range(1, X_vif_const.shape[1])] # Calcular VIF para cada feature

        # Ordenar por VIF descendente
        vif_data = vif_data.sort_values(by='VIF', ascending=False).reset_index(drop=True)

        print("\n--- Resultados VIF ---")
        print(vif_data)

        # Identificar variables con VIF alto
        high_vif_threshold = 10 # Umbral común (puedes usar 5 si quieres ser más estricto)
        high_vif_features = vif_data[vif_data['VIF'] > high_vif_threshold]['feature'].tolist()

        if high_vif_features:
            print(f"\n*** Variables con VIF > {high_vif_threshold} (potencial multicolinealidad alta): ***")
            print(high_vif_features)
        else:
            print(f"\nNo se encontraron variables con VIF > {high_vif_threshold}.")

    except Exception as e_vif:
        print(f"\nError calculando VIF: {e_vif}")
        print("Esto puede ocurrir por colinealidad perfecta (variables idénticas,")
        print("o una variable es combinación lineal exacta de otras). Revisa los pares altamente correlacionados.")
--- Calculando Variance Inflation Factor (VIF) ---
Valores > 5 indican correlación moderada-alta, > 10 indican alta correlación.

--- Resultados VIF ---
                                  feature       VIF
0              Tamaño de fuente más usado       inf
1   Formato Fecha Más Común_Mon YYYY (EN)       inf
2                       Seccion_education       inf
3                 Seccion_work_experience       inf
4                          Seccion_skills       inf
..                                    ...       ...
74                   Seccion_publications  1.200295
75                       Lineas_languages  1.197767
76                          Lineas_skills  1.191524
77           Uso de negritas (estimado %)  1.168362
78                  Lineas_certifications  1.153789

[79 rows x 2 columns]

*** Variables con VIF > 10 (potencial multicolinealidad alta): ***
['Tamaño de fuente más usado', 'Formato Fecha Más Común_Mon YYYY (EN)', 'Seccion_education', 'Seccion_work_experience', 'Seccion_skills', 'Seccion_certifications', 'Seccion_achievements', 'Seccion_professional_profile', 'Seccion_languages', 'Seccion_projects', 'Formato Fecha Más Común_SpaCy DATE (Sin clasificar)', 'Seccion_training_courses', 'Seccion_volunteer_work', 'Formato Fecha Más Común_Rango YYYY-YYYY', 'Formato Fecha Más Común_Month YYYY (EN)', 'Formato Texto (Lineas)_Mixto', 'Formato Texto (Lineas)_Párrafos', 'Formato Texto (Lineas)_Viñetas', 'Orden Temporal_Orden Temporal Detectado', 'Orden Temporal_Pocas Fechas', 'Formato Fecha Más Común_DD/MM/YYYY', 'Formato Fecha Más Común_MM-YYYY', 'Formato Fecha Más Común_MM/YYYY', 'Formato Fecha Más Común_YYYY', 'Formato Fecha Más Común_YYYY (SpaCy)', 'Fuente principal_ArialMT', 'Fuente principal_Calibri', 'secciones_completas', 'Deteccion Foto Perfil_Posible Foto Detectada', 'Tamaño cuerpo probable', 'Deteccion Foto Perfil_No se detectaron imágenes candidatas', 'Uso de colores (dibujos)_Sí', 'Uso de colores (dibujos)_No', 'Uso de colores (texto)_Sí', 'Porcentaje Lenguaje Técnico', 'Porcentaje Lenguaje Genérico', 'Uso de colores (texto)_No', 'Consistencia márgenes (aprox)_Inconsistente', 'Consistencia márgenes (aprox)_Consistente', 'Consistencia tamaños fuente_Inconsistente', 'Consistencia tamaños fuente_Consistente', 'Legibilidad general_Potencialmente Deficiente', 'Legibilidad general_Buena', 'Fuente principal_Tahoma', 'Fuente principal_Roboto-Regular', 'Fuente principal_Otra', 'Fuente principal_OpenSans-Regular', 'Fuente principal_Lato-Regular', 'Formato Fecha Más Común_Mes YYYY (ES Comp)', 'texto_extraido_len', 'Densidad_Texto_Por_Seccion']
In [39]:
df
Out[39]:
Passed Numero de Paginas Cantidad de Palabras Densidad Informacion (%) Fechas Detectadas (Count) Tamaño cuerpo probable Variedad de fuentes Variedad de tamaños Uso de negritas (estimado %) Uso de cursivas (estimado %) Porcentaje Lenguaje Técnico Porcentaje Lenguaje Genérico LinkedIn GitHub Website/Otro Cantidad de imágenes Tiene Elementos Graficos Lineas_education Lineas_work_experience Lineas_skills Lineas_certifications Lineas_achievements Lineas_professional_profile Lineas_languages Lineas_projects Lineas_publications Lineas_training_courses Lineas_volunteer_work Seccion_education Seccion_work_experience Seccion_skills Seccion_certifications Seccion_achievements Seccion_professional_profile Seccion_languages Seccion_projects Seccion_publications Seccion_training_courses Seccion_volunteer_work texto_extraido_len Tamaño de fuente más usado Promedio tamaño fuente Formato Texto (Lineas)_Mixto Formato Texto (Lineas)_Párrafos Formato Texto (Lineas)_Viñetas Orden Temporal_Orden Temporal Detectado Orden Temporal_Pocas Fechas Formato Fecha Más Común_DD/MM/YYYY Formato Fecha Más Común_MM-YYYY Formato Fecha Más Común_MM/YYYY Formato Fecha Más Común_Mes YYYY (ES Comp) Formato Fecha Más Común_Mon YYYY (EN) Formato Fecha Más Común_Month YYYY (EN) Formato Fecha Más Común_Rango YYYY-YYYY Formato Fecha Más Común_SpaCy DATE (Sin clasificar) Formato Fecha Más Común_YYYY Formato Fecha Más Común_YYYY (SpaCy) Fuente principal_ArialMT Fuente principal_Calibri Fuente principal_Lato-Regular Fuente principal_OpenSans-Regular Fuente principal_Otra Fuente principal_Roboto-Regular Fuente principal_Tahoma Legibilidad general_Buena Legibilidad general_Potencialmente Deficiente Consistencia tamaños fuente_Consistente Consistencia tamaños fuente_Inconsistente Consistencia márgenes (aprox)_Consistente Consistencia márgenes (aprox)_Inconsistente Uso de colores (texto)_No Uso de colores (texto)_Sí Uso de colores (dibujos)_No Uso de colores (dibujos)_Sí Deteccion Foto Perfil_No se detectaron imágenes candidatas Deteccion Foto Perfil_Posible Foto Detectada secciones_completas Ratio_Lineas_Experiencia_len Ratio_Lineas_Experiencia_words Densidad_Texto_Por_Seccion
0 1 2 493 5.71 3 12 7 5 34.4 91.7 3.72 96.28 1 0 1 0 0 6 2 26 0 0 0 0 9 0 0 0 1 1 1 1 0 1 0 1 1 1 0 3692 12 16.000000 0 0 1 1 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 1 0 0 1 0 1 0 1 0 0 1 0 1 1 0 7 0.000542 0.004057 527.428571
1 1 1 388 8.09 1 9 1 1 0.0 100.0 9.61 90.39 0 0 1 9 1 8 12 3 0 0 3 1 0 7 0 0 1 1 1 1 0 1 1 1 1 1 0 2703 9 9.000000 0 0 1 0 1 0 0 1 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 1 1 0 1 0 1 0 0 1 0 1 8 0.004440 0.030928 337.875000
2 1 1 378 8.27 0 10 3 4 21.8 100.0 8.58 91.42 0 0 0 0 1 3 38 1 0 0 0 0 0 0 0 0 1 1 1 1 0 1 1 1 1 1 1 2761 10 13.000000 1 0 0 0 1 0 0 0 0 1 0 0 0 0 0 1 0 0 0 0 0 0 1 0 1 0 1 0 0 1 1 0 1 0 9 0.013763 0.100529 306.777778
3 1 4 656 3.54 2 10 4 12 16.2 100.0 6.67 93.33 0 0 0 3 1 25 8 3 0 0 0 17 0 0 18 0 1 1 1 0 0 1 1 1 1 1 0 4732 10 14.916667 0 0 1 1 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 1 0 0 1 0 0 1 0 1 1 0 0 1 0 1 7 0.001691 0.012195 676.000000
4 1 3 160 4.71 0 10 6 7 31.2 5.2 11.29 88.71 1 1 0 5 1 0 7 0 0 2 5 8 2 3 1 0 1 1 1 1 1 1 1 1 1 1 1 4562 10 13.714286 0 0 1 0 1 0 0 0 0 0 0 0 0 1 0 0 0 1 0 0 0 0 1 0 0 1 1 0 0 1 1 0 0 1 10 0.001534 0.043750 456.200000
... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ...
630 0 6 1372 4.37 0 11 8 6 32.7 36.8 6.72 93.28 0 0 1 8 1 6 5 0 6 1 0 3 3 6 6 0 1 1 1 1 1 1 1 1 1 1 0 8464 11 13.166667 0 0 1 0 1 0 0 0 0 1 0 0 0 0 0 0 1 0 0 0 0 0 1 0 0 1 0 1 0 1 0 1 0 1 9 0.000591 0.003644 940.444444
631 0 10 3729 7.54 3 11 7 8 8.1 5.4 2.71 97.29 0 0 0 1 1 0 0 2 4 0 12 0 34 0 5 0 1 0 1 1 1 1 1 1 1 1 0 25210 11 13.125000 0 0 1 1 0 0 0 0 0 0 0 0 0 1 0 0 1 0 0 0 0 0 1 0 0 1 1 0 1 0 0 1 1 0 8 0.000000 0.000000 3151.250000
632 0 3 899 6.13 1 11 4 6 62.7 4.5 5.04 94.96 0 0 0 0 1 5 8 12 0 17 1 1 35 0 0 4 1 1 1 1 1 1 1 1 1 1 1 6154 11 14.166667 0 0 1 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 1 0 0 1 0 0 1 1 0 1 0 1 0 1 0 10 0.001300 0.008899 615.400000
633 0 1 185 3.93 2 10 2 4 0.0 100.0 6.25 93.75 0 0 0 0 1 0 1 5 0 0 5 5 3 0 2 0 1 1 1 1 0 1 1 1 1 1 0 1313 10 18.000000 0 0 1 1 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 1 0 0 1 0 1 0 1 0 1 0 0 1 1 0 8 0.000762 0.005405 164.125000
634 0 4 534 5.95 0 11 3 2 39.9 0.5 5.55 94.45 1 0 0 2 1 1 0 2 4 1 0 1 1 4 0 0 1 1 1 1 1 1 1 1 1 1 1 7693 11 10.500000 0 0 1 0 1 0 0 0 1 0 0 0 0 0 0 0 0 0 0 1 0 0 1 0 1 0 0 1 0 1 0 1 0 1 10 0.000000 0.000000 769.300000

614 rows × 80 columns

Eliminación de variables¶

Eliminaremos las variables con VIF Infinito o grande, así como con alta correlacion entre ellas que puedan estar causando multicolinealidad.

In [40]:
print("--- Eliminando Variables Redundantes / Multicolineares ---")

# --- Definir lista de variables a ELIMINAR ---
variables_to_drop = [
    # Perfecta (-1.0) / Complementarias / One-Hot (Mantener 1 de cada par/grupo)
    'Porcentaje Lenguaje Genérico', # Mantener 'Porcentaje Lenguaje Técnico'
    'Orden Temporal_Pocas Fechas', # Mantener 'Orden Temporal_Orden Temporal Detectado'
    'Legibilidad general_Potencialmente Deficiente', # Mantener 'Legibilidad general_Buena'
    'Legibilidad general_Vacío', # Mantener 'Legibilidad general_Buena' como referencia principal
    'Consistencia tamaños fuente_Inconsistente', # Mantener 'Consistencia tamaños fuente_Consistente'
    'Consistencia márgenes (aprox)_Inconsistente', # Mantener 'Consistencia márgenes (aprox)_Consistente'
    'Uso de colores (texto)_No', # Mantener 'Uso de colores (texto)_Sí'
    'Uso de colores (dibujos)_No', # Mantener 'Uso de colores (dibujos)_Sí'
    'Deteccion Foto Perfil_No se detectaron imágenes candidatas', # Mantener 'Deteccion Foto Perfil_Posible Foto Detectada'

    # Perfecta (1.0)
    'Tamaño de fuente más usado', # Mantener 'Tamaño cuerpo probable' (o 'Promedio tamaño fuente')

    # Alta Correlación / Redundancia / Alto VIF
    'Cantidad de Palabras', # Mantener 'texto_extraido_len'
    'Ratio_Lineas_Experiencia_words', # Mantener 'Ratio_Lineas_Experiencia_len'
    'Densidad_Texto_Por_Seccion', # Muy correlacionada con 'texto_extraido_len'

    # Flags de Sección Individuales (Redundantes con 'secciones_completas')
    # Mantenemos 'secciones_completas' (fuerte en T-test)
    # Mantenemos 'Seccion_training_courses' (significativa Chi2)
    # Mantenemos 'Seccion_languages' y 'Seccion_publications' (borderline Chi2, revisar VIF final)
    'Seccion_education',
    'Seccion_work_experience',
    'Seccion_skills',
    'Seccion_achievements',
    'Seccion_professional_profile',
    'Seccion_projects',
    'Seccion_volunteer_work',
    'Seccion_certifications', # También tenía VIF infinito y no fue signif. en Chi2

    # Limpieza One-Hot Encoding (K-1) - **¡¡REVISAR Y AJUSTAR ESTAS!!**
    # Formato Texto (Lineas): Asumiendo 3 categorías, eliminamos 1 (ej. Mixto)
    'Formato Texto (Lineas)_Mixto', # Mantenemos _Párrafos y _Viñetas

    # Fuente principal: Eliminamos la mayoría, mantenemos _Tahoma (borderline) y _Otra (si existe)
    # Ajusta esto basado en las fuentes reales y cuáles quieres mantener como referencia
    'Fuente principal_Lato-Regular',
    'Fuente principal_OpenSans-Regular',
    'Fuente principal_Roboto-Regular',
    'Fuente principal_Ninguna',
    # Mantenemos 'Fuente principal_Tahoma' y 'Fuente principal_Otra' (si existe)

    # Formato Fecha Más Común: Eliminamos la mayoría. Mantenemos _MM/YYYY (borderline) y quizás la más común.
    # Ajusta basado en tus formatos reales y su frecuencia/importancia
    'Formato Fecha Más Común_DD/MM/YYYY',
    'Formato Fecha Más Común_Mes YYYY (ES Comp)', # Asegúrate que este nombre sea correcto
    'Formato Fecha Más Común_Month YYYY (EN)', # Asegúrate que este nombre sea correcto
    'Formato Fecha Más Común_Rango YYYY-YYYY', # Asegúrate que este nombre sea correcto
    'Formato Fecha Más Común_SpaCy DATE (Sin clasificar)',
    'Formato Fecha Más Común_YYYY (SpaCy)',
    # Mantenemos 'Formato Fecha Más Común_MM/YYYY'
    # Mantenemos 'Formato Fecha Más Común_YYYY (EN)' (Ejemplo, si es la más común)

    # Columna índice sin nombre (si existe)
    # El archivo CSV empezaba con ',', así que la primera columna es probablemente el índice
    df.columns[0] # Añade el nombre de la primera columna a la lista
]

# Filtrar la lista para asegurar que solo intentamos eliminar columnas que realmente existen en df
variables_existentes_a_eliminar = [col for col in variables_to_drop if col in df.columns]
variables_no_encontradas = [col for col in variables_to_drop if col not in df.columns]

if variables_no_encontradas:
    print("\nAdvertencia: Las siguientes variables a eliminar no se encontraron en el DataFrame:")
    print(variables_no_encontradas)

# Crear el nuevo DataFrame reducido
df_reducido = df.drop(columns=variables_existentes_a_eliminar, errors='ignore') # errors='ignore' por si acaso

print(f"\nSe eliminaron {len(variables_existentes_a_eliminar)} variables.")
# print("Variables eliminadas:", variables_existentes_a_eliminar) # Descomentar si quieres ver la lista completa
print(f"\nQuedan {df_reducido.shape[1]} columnas.")
print("Variables restantes:", df_reducido.columns.tolist())


# --- Paso 2: Recalcular VIF en el DataFrame Reducido ---
print("\n--- Calculando VIF en el conjunto reducido de features ---")
print("Idealmente, la mayoría de los VIFs deberían ser < 5 o < 10.")

# Seleccionar predictores del df reducido (todas menos 'Passed')
if 'Passed' in df_reducido.columns:
    X_reducido = df_reducido.drop(columns=['Passed'])
else:
    print("Advertencia: No se encontró la columna 'Passed' en df_reducido.")
    X_reducido = df_reducido.copy()

# Asegurar que son numéricas
X_reducido = X_reducido.select_dtypes(include=np.number)

# Verificar NaNs de nuevo
if X_reducido.isnull().sum().sum() > 0:
    print("Error: Se encontraron NaNs en las features reducidas. Revisar proceso de limpieza/imputación.")
    # Considera imputar aquí si es necesario:
    # imputer_reducido = SimpleImputer(strategy='mean')
    # X_reducido = pd.DataFrame(imputer_reducido.fit_transform(X_reducido), columns=X_reducido.columns)
    # print("NaNs imputados en el conjunto reducido.")
else:
    # Añadir constante
    X_reducido_const = add_constant(X_reducido, prepend=True, has_constant='raise') # has_constant='raise' por si ya existe

    # Calcular VIF
    try:
        vif_data_reducido = pd.DataFrame()
        vif_data_reducido["feature"] = X_reducido_const.columns[1:] # Nombres originales
        # Calcular VIF para cada feature
        vif_values = []
        for i in range(1, X_reducido_const.shape[1]):
            try:
                 vif = variance_inflation_factor(X_reducido_const.values, i)
                 vif_values.append(vif)
            except Exception as e_vif_calc:
                 print(f"  - Advertencia: No se pudo calcular VIF para {X_reducido_const.columns[i+1]}. Asignando Inf. Error: {e_vif_calc}")
                 vif_values.append(np.inf) # Asignar infinito si hay error

        vif_data_reducido["VIF"] = vif_values


        # Ordenar y mostrar
        vif_data_reducido = vif_data_reducido.sort_values(by='VIF', ascending=False).reset_index(drop=True)
        print("\n--- Resultados VIF (Reducido) ---")
        pd.set_option('display.max_rows', None) # Mostrar todas las filas
        print(vif_data_reducido)
        pd.reset_option('display.max_rows') # Restaurar opción

        # Verificar si aún hay VIFs altos
        high_vif_threshold = 10 # Umbral común
        high_vif_features_reducido = vif_data_reducido[vif_data_reducido['VIF'] > high_vif_threshold]['feature'].tolist()
        if high_vif_features_reducido:
            print(f"\n*** ALERTA: Variables con VIF > {high_vif_threshold} aún presentes en el conjunto reducido: ***")
            print(high_vif_features_reducido)
        else:
            print(f"\n¡Bien! No se encontraron variables con VIF > {high_vif_threshold} en el conjunto reducido.")

    except Exception as e_vif_reducido:
        print(f"\nError general calculando VIF en el conjunto reducido: {e_vif_reducido}")
        print("Revisa si aún existe colinealidad perfecta.")
--- Eliminando Variables Redundantes / Multicolineares ---

Advertencia: Las siguientes variables a eliminar no se encontraron en el DataFrame:
['Legibilidad general_Vacío', 'Fuente principal_Ninguna']

Se eliminaron 31 variables.

Quedan 49 columnas.
Variables restantes: ['Numero de Paginas', 'Densidad Informacion (%)', 'Fechas Detectadas (Count)', 'Tamaño cuerpo probable', 'Variedad de fuentes', 'Variedad de tamaños', 'Uso de negritas (estimado %)', 'Uso de cursivas (estimado %)', 'Porcentaje Lenguaje Técnico', 'LinkedIn', 'GitHub', 'Website/Otro', 'Cantidad de imágenes', 'Tiene Elementos Graficos', 'Lineas_education', 'Lineas_work_experience', 'Lineas_skills', 'Lineas_certifications', 'Lineas_achievements', 'Lineas_professional_profile', 'Lineas_languages', 'Lineas_projects', 'Lineas_publications', 'Lineas_training_courses', 'Lineas_volunteer_work', 'Seccion_languages', 'Seccion_publications', 'Seccion_training_courses', 'texto_extraido_len', 'Promedio tamaño fuente', 'Formato Texto (Lineas)_Párrafos', 'Formato Texto (Lineas)_Viñetas', 'Orden Temporal_Orden Temporal Detectado', 'Formato Fecha Más Común_MM-YYYY', 'Formato Fecha Más Común_MM/YYYY', 'Formato Fecha Más Común_Mon YYYY (EN)', 'Formato Fecha Más Común_YYYY', 'Fuente principal_ArialMT', 'Fuente principal_Calibri', 'Fuente principal_Otra', 'Fuente principal_Tahoma', 'Legibilidad general_Buena', 'Consistencia tamaños fuente_Consistente', 'Consistencia márgenes (aprox)_Consistente', 'Uso de colores (texto)_Sí', 'Uso de colores (dibujos)_Sí', 'Deteccion Foto Perfil_Posible Foto Detectada', 'secciones_completas', 'Ratio_Lineas_Experiencia_len']

--- Calculando VIF en el conjunto reducido de features ---
Idealmente, la mayoría de los VIFs deberían ser < 5 o < 10.
Advertencia: No se encontró la columna 'Passed' en df_reducido.

--- Resultados VIF (Reducido) ---
                                         feature       VIF
0                         Lineas_work_experience  5.483628
1                             texto_extraido_len  4.763881
2                   Ratio_Lineas_Experiencia_len  4.598712
3                              Numero de Paginas  3.889616
4                          Fuente principal_Otra  3.206462
5                         Promedio tamaño fuente  3.199315
6                         Tamaño cuerpo probable  3.145225
7                            Variedad de tamaños  3.121028
8                      Fechas Detectadas (Count)  2.839919
9        Orden Temporal_Orden Temporal Detectado  2.827062
10       Consistencia tamaños fuente_Consistente  2.815092
11                      Fuente principal_ArialMT  2.774988
12                      Fuente principal_Calibri  2.437709
13                      Densidad Informacion (%)  2.388989
14                           secciones_completas  2.074818
15     Consistencia márgenes (aprox)_Consistente  1.997336
16                       Fuente principal_Tahoma  1.760622
17                  Uso de cursivas (estimado %)  1.721857
18                     Uso de colores (texto)_Sí  1.606982
19                   Uso de colores (dibujos)_Sí  1.605743
20                          Cantidad de imágenes  1.605412
21                  Formato Fecha Más Común_YYYY  1.600365
22                                      LinkedIn  1.557118
23                      Seccion_training_courses  1.500559
24                     Legibilidad general_Buena  1.498338
25         Formato Fecha Más Común_Mon YYYY (EN)  1.423896
26                Formato Texto (Lineas)_Viñetas  1.420840
27  Deteccion Foto Perfil_Posible Foto Detectada  1.408555
28                                        GitHub  1.393848
29                             Seccion_languages  1.387845
30               Formato Fecha Más Común_MM/YYYY  1.326532
31                           Variedad de fuentes  1.305740
32               Formato Texto (Lineas)_Párrafos  1.280305
33                       Lineas_training_courses  1.272754
34                      Tiene Elementos Graficos  1.243426
35                                  Website/Otro  1.236787
36                   Porcentaje Lenguaje Técnico  1.235242
37                               Lineas_projects  1.226351
38                         Lineas_volunteer_work  1.221729
39                           Lineas_publications  1.207565
40                           Lineas_achievements  1.186774
41                              Lineas_education  1.170561
42                              Lineas_languages  1.149709
43                          Seccion_publications  1.133091
44                                 Lineas_skills  1.128096
45                  Uso de negritas (estimado %)  1.124607
46                         Lineas_certifications  1.111321
47                   Lineas_professional_profile  1.106284
48               Formato Fecha Más Común_MM-YYYY  1.089613

¡Bien! No se encontraron variables con VIF > 10 en el conjunto reducido.
In [41]:
variable_passed = df['Passed']
df_reducido['Passed'] = variable_passed
In [42]:
df_reducido
Out[42]:
Numero de Paginas Densidad Informacion (%) Fechas Detectadas (Count) Tamaño cuerpo probable Variedad de fuentes Variedad de tamaños Uso de negritas (estimado %) Uso de cursivas (estimado %) Porcentaje Lenguaje Técnico LinkedIn GitHub Website/Otro Cantidad de imágenes Tiene Elementos Graficos Lineas_education Lineas_work_experience Lineas_skills Lineas_certifications Lineas_achievements Lineas_professional_profile Lineas_languages Lineas_projects Lineas_publications Lineas_training_courses Lineas_volunteer_work Seccion_languages Seccion_publications Seccion_training_courses texto_extraido_len Promedio tamaño fuente Formato Texto (Lineas)_Párrafos Formato Texto (Lineas)_Viñetas Orden Temporal_Orden Temporal Detectado Formato Fecha Más Común_MM-YYYY Formato Fecha Más Común_MM/YYYY Formato Fecha Más Común_Mon YYYY (EN) Formato Fecha Más Común_YYYY Fuente principal_ArialMT Fuente principal_Calibri Fuente principal_Otra Fuente principal_Tahoma Legibilidad general_Buena Consistencia tamaños fuente_Consistente Consistencia márgenes (aprox)_Consistente Uso de colores (texto)_Sí Uso de colores (dibujos)_Sí Deteccion Foto Perfil_Posible Foto Detectada secciones_completas Ratio_Lineas_Experiencia_len Passed
0 2 5.71 3 12 7 5 34.4 91.7 3.72 1 0 1 0 0 6 2 26 0 0 0 0 9 0 0 0 0 1 1 3692 16.000000 0 1 1 0 0 1 0 0 0 1 0 1 1 1 1 1 0 7 0.000542 1
1 1 8.09 1 9 1 1 0.0 100.0 9.61 0 0 1 9 1 8 12 3 0 0 3 1 0 7 0 0 1 1 1 2703 9.000000 0 1 0 0 1 0 0 0 0 1 0 0 1 1 0 1 1 8 0.004440 1
2 1 8.27 0 10 3 4 21.8 100.0 8.58 0 0 0 0 1 3 38 1 0 0 0 0 0 0 0 0 1 1 1 2761 13.000000 0 0 0 0 0 1 0 1 0 0 0 1 1 1 1 0 0 9 0.013763 1
3 4 3.54 2 10 4 12 16.2 100.0 6.67 0 0 0 3 1 25 8 3 0 0 0 17 0 0 18 0 1 1 1 4732 14.916667 0 1 1 0 0 0 0 0 0 1 0 1 0 0 0 1 1 7 0.001691 1
4 3 4.71 0 10 6 7 31.2 5.2 11.29 1 1 0 5 1 0 7 0 0 2 5 8 2 3 1 0 1 1 1 4562 13.714286 0 1 0 0 0 0 1 0 0 0 0 1 0 1 1 0 1 10 0.001534 1
... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ...
630 6 4.37 0 11 8 6 32.7 36.8 6.72 0 0 1 8 1 6 5 0 6 1 0 3 3 6 6 0 1 1 1 8464 13.166667 0 1 0 0 0 1 0 0 1 0 0 1 0 0 1 1 1 9 0.000591 0
631 10 7.54 3 11 7 8 8.1 5.4 2.71 0 0 0 1 1 0 0 2 4 0 12 0 34 0 5 0 1 1 1 25210 13.125000 0 1 1 0 0 0 1 0 1 0 0 1 0 1 0 1 0 8 0.000000 0
632 3 6.13 1 11 4 6 62.7 4.5 5.04 0 0 0 0 1 5 8 12 0 17 1 1 35 0 0 4 1 1 1 6154 14.166667 0 1 0 0 0 0 0 0 0 1 0 1 0 1 0 0 0 10 0.001300 0
633 1 3.93 2 10 2 4 0.0 100.0 6.25 0 0 0 0 1 0 1 5 0 0 5 5 3 0 2 0 1 1 1 1313 18.000000 0 1 1 0 0 0 1 0 0 1 0 1 1 1 0 1 0 8 0.000762 0
634 4 5.95 0 11 3 2 39.9 0.5 5.55 1 0 0 2 1 1 0 2 4 1 0 1 1 4 0 0 1 1 1 7693 10.500000 0 1 0 0 0 0 0 0 0 1 0 1 1 0 1 1 1 10 0.000000 0

614 rows × 50 columns

In [43]:
df_reducido.to_csv('../Bases/base_cvs/datos_para_clusterisar.csv', index=False)

Feature importance (otra vez)¶

Al realizar el feature importance sin el ruido de la multicolinealidad, posiblemente obtengamos insights en mejores variables para un modelo predictivo que los t-test y chi-cuadrado ignoraron por no ser tan lineales.

In [44]:
# --- Asumiendo que 'df_reducido' es tu DataFrame después de eliminar variables ---

print("--- Recalculando Feature Importance con el conjunto reducido ---")

# --- 1. Preparar Datos (usando df_reducido) ---
target_column = 'Passed'

if target_column not in df_reducido.columns:
    print(f"Error: La columna objetivo '{target_column}' no está en df_reducido.")
    # Salir o manejar el error
    X_final = None
else:
    X_final = df_reducido.drop(columns=[target_column])
    y_final = df_reducido[target_column]

    # Verificar y eliminar columnas con varianza cero (como la posible 'Fuente principal_Ninguna')
    cols_antes = X_final.shape[1]
    variances = X_final.var()
    cols_zero_variance = variances[variances <= 1e-8].index.tolist() # Umbral muy pequeño
    if cols_zero_variance:
        print(f"Eliminando {len(cols_zero_variance)} columnas con varianza cercana a cero: {cols_zero_variance}")
        X_final = X_final.drop(columns=cols_zero_variance)
        print(f"Quedan {X_final.shape[1]} features para el análisis.")

    feature_names_final = X_final.columns

    # Verificar NaNs (no deberían quedar, pero por si acaso)
    if X_final.isnull().sum().sum() > 0:
        print(f"ADVERTENCIA: Se encontraron {X_final.isnull().sum().sum()} NaNs en el DataFrame reducido. Imputando con la media...")
        imputer_final = SimpleImputer(strategy='mean')
        X_final = pd.DataFrame(imputer_final.fit_transform(X_final), columns=feature_names_final)
    else:
        print("No se encontraron valores NaN en las features finales.")


    # --- 2. Entrenar Random Forest (con datos reducidos) ---
    print("\nEntrenando Random Forest con el conjunto de features reducido...")
    rf_model_final = RandomForestClassifier(n_estimators=150,
                                             random_state=42,
                                             n_jobs=-1,
                                             class_weight='balanced',
                                             oob_score=True)

    rf_model_final.fit(X_final, y_final)
    print(f"Modelo (reducido) entrenado. OOB Score: {rf_model_final.oob_score_:.4f}")

    # --- 3. Extraer y Mostrar Importancia (con datos reducidos) ---
    print("\nCalculando y mostrando importancia de variables (conjunto reducido)...")
    importances_final = rf_model_final.feature_importances_

    importance_df_final = pd.DataFrame({'Feature': feature_names_final, 'Importance': importances_final})
    importance_df_final = importance_df_final.sort_values(by='Importance', ascending=False).reset_index(drop=True)

    print("\n--- Importancia de Variables según Random Forest (Conjunto Reducido - Top 30) ---")
    pd.set_option('display.max_rows', 30) # Mostrar hasta 30 filas
    print(importance_df_final.head(30))
    pd.reset_option('display.max_rows') # Restaurar opción

    # --- 4. Graficar Importancias (Opcional) ---
    print("\nGenerando gráfico de importancia (reducido - Top 25)...")
    try:
        plt.figure(figsize=(12, 10)) # Ajustar tamaño si es necesario
        n_top_features_plot = 25
        # Asegurarse de que no intentamos graficar más features de las que hay
        n_top_features_plot = min(n_top_features_plot, len(importance_df_final))
        sns.barplot(x='Importance', y='Feature', data=importance_df_final.head(n_top_features_plot), palette='viridis')
        plt.title(f'Top {n_top_features_plot} Feature Importances (Random Forest - Reduced Features)')
        plt.xlabel('Importance Score')
        plt.ylabel('Feature')
        plt.tight_layout()
        plt.show()
    except ImportError:
        print("\nPara graficar, necesitas instalar matplotlib y seaborn:")
        print("pip install matplotlib seaborn")
    except Exception as e_plot:
        print(f"\nNo se pudo generar el gráfico: {e_plot}")
--- Recalculando Feature Importance con el conjunto reducido ---
No se encontraron valores NaN en las features finales.

Entrenando Random Forest con el conjunto de features reducido...
Modelo (reducido) entrenado. OOB Score: 0.5342

Calculando y mostrando importancia de variables (conjunto reducido)...

--- Importancia de Variables según Random Forest (Conjunto Reducido - Top 30) ---
                         Feature  Importance
0    Porcentaje Lenguaje Técnico    0.060878
1   Uso de negritas (estimado %)    0.059902
2             texto_extraido_len    0.056464
3       Densidad Informacion (%)    0.052648
4         Promedio tamaño fuente    0.048213
5   Ratio_Lineas_Experiencia_len    0.046659
6               Lineas_education    0.039764
7         Lineas_work_experience    0.039081
8    Lineas_professional_profile    0.035266
9                  Lineas_skills    0.035232
10           Variedad de tamaños    0.034025
11           Lineas_publications    0.032974
12           Variedad de fuentes    0.030555
13  Uso de cursivas (estimado %)    0.030237
14              Lineas_languages    0.029565
15               Lineas_projects    0.028890
16       Lineas_training_courses    0.028357
17     Fechas Detectadas (Count)    0.024019
18           secciones_completas    0.023208
19        Tamaño cuerpo probable    0.022682
20          Cantidad de imágenes    0.022565
21             Numero de Paginas    0.020787
22         Lineas_certifications    0.018504
23         Lineas_volunteer_work    0.017379
24           Lineas_achievements    0.015407
25                  Website/Otro    0.009125
26                      LinkedIn    0.009088
27         Fuente principal_Otra    0.008396
28      Seccion_training_courses    0.008250
29      Tiene Elementos Graficos    0.007779

Generando gráfico de importancia (reducido - Top 25)...
No description has been provided for this image

Conclusiones antes de Modelar¶

En primer lugar, vemos que eliminar las variables con multicolinealidad nos dio un OOB Score de casi 53%, dejandonos con la impresión de que mejora un poco en predicción, aunque no es suficiente y es necesario continuar explorando nuestras variables para llegar a una mayor precisión.

Por otro lado, la feature importance nos trae que aunque en términos de medias, la variable Porcentaje Lenguaje Técnico no parecía importante para pasar o no, de acuerdo a la clasificación Random Forest si puede llegar a ser importante para la predicción. Siendo así podemos decir que tener un mayor % de lenguaje técnico puede que haga que una HV pase a una siguiente étapa.

De la misma manera, se mantienen en importancia la longitud del texto extraido así como el uso de negritas estimado, variables que veíamos en las pruebas anteriores mostraban importancia.

De la misma manera, todas las variables que en las pruebas t-test y Chi-cuadrado se encuentran dentro del top-30, aunque distribuidas, confirman la importancia de las mismas para un eventual modelo.

Antes de modelar:¶

  • El Random Forest sigue sugiriendo que la predicción es difícil (OOB bajo). Por lo mismo, intentaremos seguir el refinamiento de variables y buscar aumentar su posibilidad o no de avanzar.
  • Las variables más importantes parecen ser una mezcla de contenido (% Técnico, longitud), estilo (% Negritas, tamaño fuente) y estructura (Lineas_..., secciones_completas).

La base para empezar el modelado quedará¶

Variables Numéricas:¶
  • Porcentaje Lenguaje Técnico (RF Alto)
  • texto_extraido_len (T-test signif, RF Alto)
  • Uso de negritas (estimado %) (RF Alto, T-test Border)
  • Densidad Informacion (%) (RF Moderado)
  • Ratio_Lineas_Experiencia_len (RF Moderado)
  • Promedio tamaño fuente (RF Moderado)
  • Lineas_work_experience (RF Moderado)
  • Lineas_training_courses (RF Moderado, Sección signif Chi2)
  • Variedad de tamaños (RF Moderado)
  • secciones_completas (T-test signif, RF Bajo-Medio)
  • Numero de Paginas (T-test Border, RF Bajo)
  • Variedad de tamaños(VIF bajo)
  • Variedad de fuentes(VIF bajo)
  • Uso de cursivas (estimado %) (VIF bajo)
  • Cantidad de imágenes (VIF bajo)
  • Fechas Detectadas (RF Moderado)
Variables Binarias (0/1):¶
  • Website/Otro (Chi2 signif)
  • Seccion_training_courses (Flag - Chi2 signif)
  • Uso de colores (texto)_Sí (Chi2 Border)
  • Legibilidad general_Buena (Para representar legibilidad)
  • Consistencia tamaños fuente_Consistente (Para representar consistencia)
  • Orden Temporal_Orden Temporal Detectado (Representa Orden Temporal)
  • Legibilidad general_Buena (Representa Legibilidad)
  • Consistencia tamaños fuente_Consistente (Representa Consistencia Tamaño)
  • Consistencia márgenes (aprox)_Consistente (Representa Consistencia Márgenes)
  • Deteccion Foto Perfil_Posible Foto Detectada (Representa si tiene foto)
  • Formato Texto (Lineas)_Párrafos (Representa el tipo de texto Parrafo)
  • Formato Texto (Lineas)_Viñetas' (Representa el tipo de texto Viñetas o 'Bullet points')
  • Fuente principal_Tahoma (borderline Chi2)
  • Fuente principal_Otra (Representa otro tipo de fuentes)
  • Formato Fecha Más Común_MM/YYYY' (borderline Chi2)
  • Formato Fecha Más Común_YYYY (EN) (Formato de fecha más frecuente)
  • Tiene Elementos Graficos (VIF bajo)
  • LinkedIn (VIF bajo)
  • GitHub (VIF bajo)
  • Seccion_languages (Borderline Chi2, VIF bajo)
  • Seccion_publications (Borderline Chi2, VIF bajo)

De acuerdo con lo anterior, vemos que tenemos variables que representan las características que buscabamos extraer, además de las que cuentan con score RF alto o moderado, tienen un VIF bajo y fueron relevantes en las pruebas t-test y chi-cuadrado.

In [45]:
# Asumiendo que 'df_reducido' es tu DataFrame DESPUÉS de eliminar las variables
# con alta multicolinealidad/redundancia y CUALQUIER columna con varianza cero
# (como 'Fuente principal_Ninguna' si fue el caso).

print(f"Número de columnas en df_reducido antes de seleccionar: {df_reducido.shape[1]}")
print("Columnas disponibles:", df_reducido.columns.tolist())

# --- 1. Definir las columnas FINALES para guardar ---
# (Basado en la interpretación de T-test, Chi2, RF y VIF final)
columns_to_keep_for_modeling = [
    'Passed', # ¡Importante incluir la variable objetivo!

    # --- Features Numéricas Seleccionadas ---
    'secciones_completas',
    'texto_extraido_len',
    'Porcentaje Lenguaje Técnico',
    'Uso de negritas (estimado %)',
    'Ratio_Lineas_Experiencia_len',
    'Promedio tamaño fuente',           # Métrica de tamaño de fuente elegida
    'Densidad Informacion (%)',
    'Lineas_training_courses',        # Conteo de líneas para la sección signif.
    'Numero de Paginas',
    'Variedad de tamaños',            # VIF bajo
    'Variedad de fuentes',            # VIF bajo
    'Uso de cursivas (estimado %)',   # VIF bajo
    'Cantidad de imágenes',           # VIF bajo
    'Fechas Detectadas (Count)',    # VIF bajo

    # --- Features Binarias Seleccionadas (Flags / Dummies K-1) ---
    'Website/Otro',                   # Significativa Chi2
    'Seccion_training_courses',       # Flag - Significativa Chi2
    'Uso de colores (texto)_Sí',      # Borderline Chi2, VIF bajo
    'Orden Temporal_Orden Temporal Detectado', # Representa Orden Temporal
    'Legibilidad general_Buena',      # Representa Legibilidad
    'Consistencia tamaños fuente_Consistente', # Representa Consistencia Tamaño
    'Consistencia márgenes (aprox)_Consistente',# Representa Consistencia Márgenes
    'Deteccion Foto Perfil_Posible Foto Detectada', # Representa Foto
    'Formato Texto (Lineas)_Párrafos', # Dummy 1 para Formato Texto (asumiendo 3 cats)
    'Formato Texto (Lineas)_Viñetas',  # Dummy 2 para Formato Texto
    'Fuente principal_Tahoma',         # Dummy específico de Fuente (borderline Chi2)
    'Fuente principal_Otra',        # Opcional: Incluir si es una categoría relevante que quedó
    'Formato Fecha Más Común_MM/YYYY',# Dummy específico de Fecha (borderline Chi2)
    'Formato Fecha Más Común_YYYY',
    'Tiene Elementos Graficos',       # VIF bajo, mantener por ahora
    'LinkedIn',                       # VIF bajo, mantener por ahora
    'GitHub',                         # VIF bajo, mantener por ahora
    'Seccion_languages',            # Opcional: Borderline Chi2, VIF bajo
    'Seccion_publications',         # Opcional: Borderline Chi2, VIF bajo
]

# --- 2. Verificar y Crear DataFrame Final ---

# Asegurarse de que todas las columnas seleccionadas realmente existen en df_reducido
existing_cols_to_keep = [col for col in columns_to_keep_for_modeling if col in df_reducido.columns]
missing_cols = [col for col in columns_to_keep_for_modeling if col not in df_reducido.columns]

if missing_cols:
    print("\nADVERTENCIA: Las siguientes columnas seleccionadas NO existen en df_reducido y serán omitidas:")
    print(missing_cols)
    print("Revisa la lista 'columns_to_keep_for_modeling' o el proceso de limpieza previo.")

if not existing_cols_to_keep or 'Passed' not in existing_cols_to_keep:
     print("\nERROR: No se pueden guardar los datos. Faltan columnas esenciales ('Passed') o la lista está vacía.")
else:
     # Crear el DataFrame final solo con las columnas seleccionadas y existentes
     df_modelar = df_reducido[existing_cols_to_keep].copy()
     print(f"\nSe ha creado el DataFrame 'df_modelar' con {df_modelar.shape[1]} columnas (incluyendo 'Passed').")
     print("Columnas finales:", df_modelar.columns.tolist())

     # --- 3. Guardar en CSV ---
     output_csv_path = '../Bases/base_cvs/datos_para_modelar_cv.csv' # Nombre del archivo de salida
     try:
          # index=False evita que pandas guarde el índice del DataFrame como una columna en el CSV
          # encoding='utf-8-sig' ayuda a la compatibilidad con Excel para caracteres especiales
          df_modelar.to_csv(output_csv_path, index=False, encoding='utf-8-sig')
          print(f"\n¡DataFrame para modelado guardado exitosamente en '{output_csv_path}'!")
          print("Puedes cargar este archivo en tu nuevo notebook.")
     except Exception as e_save:
          print(f"\nError al guardar el archivo CSV: {e_save}")
Número de columnas en df_reducido antes de seleccionar: 50
Columnas disponibles: ['Numero de Paginas', 'Densidad Informacion (%)', 'Fechas Detectadas (Count)', 'Tamaño cuerpo probable', 'Variedad de fuentes', 'Variedad de tamaños', 'Uso de negritas (estimado %)', 'Uso de cursivas (estimado %)', 'Porcentaje Lenguaje Técnico', 'LinkedIn', 'GitHub', 'Website/Otro', 'Cantidad de imágenes', 'Tiene Elementos Graficos', 'Lineas_education', 'Lineas_work_experience', 'Lineas_skills', 'Lineas_certifications', 'Lineas_achievements', 'Lineas_professional_profile', 'Lineas_languages', 'Lineas_projects', 'Lineas_publications', 'Lineas_training_courses', 'Lineas_volunteer_work', 'Seccion_languages', 'Seccion_publications', 'Seccion_training_courses', 'texto_extraido_len', 'Promedio tamaño fuente', 'Formato Texto (Lineas)_Párrafos', 'Formato Texto (Lineas)_Viñetas', 'Orden Temporal_Orden Temporal Detectado', 'Formato Fecha Más Común_MM-YYYY', 'Formato Fecha Más Común_MM/YYYY', 'Formato Fecha Más Común_Mon YYYY (EN)', 'Formato Fecha Más Común_YYYY', 'Fuente principal_ArialMT', 'Fuente principal_Calibri', 'Fuente principal_Otra', 'Fuente principal_Tahoma', 'Legibilidad general_Buena', 'Consistencia tamaños fuente_Consistente', 'Consistencia márgenes (aprox)_Consistente', 'Uso de colores (texto)_Sí', 'Uso de colores (dibujos)_Sí', 'Deteccion Foto Perfil_Posible Foto Detectada', 'secciones_completas', 'Ratio_Lineas_Experiencia_len', 'Passed']

Se ha creado el DataFrame 'df_modelar' con 34 columnas (incluyendo 'Passed').
Columnas finales: ['Passed', 'secciones_completas', 'texto_extraido_len', 'Porcentaje Lenguaje Técnico', 'Uso de negritas (estimado %)', 'Ratio_Lineas_Experiencia_len', 'Promedio tamaño fuente', 'Densidad Informacion (%)', 'Lineas_training_courses', 'Numero de Paginas', 'Variedad de tamaños', 'Variedad de fuentes', 'Uso de cursivas (estimado %)', 'Cantidad de imágenes', 'Fechas Detectadas (Count)', 'Website/Otro', 'Seccion_training_courses', 'Uso de colores (texto)_Sí', 'Orden Temporal_Orden Temporal Detectado', 'Legibilidad general_Buena', 'Consistencia tamaños fuente_Consistente', 'Consistencia márgenes (aprox)_Consistente', 'Deteccion Foto Perfil_Posible Foto Detectada', 'Formato Texto (Lineas)_Párrafos', 'Formato Texto (Lineas)_Viñetas', 'Fuente principal_Tahoma', 'Fuente principal_Otra', 'Formato Fecha Más Común_MM/YYYY', 'Formato Fecha Más Común_YYYY', 'Tiene Elementos Graficos', 'LinkedIn', 'GitHub', 'Seccion_languages', 'Seccion_publications']

¡DataFrame para modelado guardado exitosamente en '../Bases/base_cvs/datos_para_modelar_cv.csv'!
Puedes cargar este archivo en tu nuevo notebook.